1de311aa8SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0
2796b7abbSSøren Andersen /*
3796b7abbSSøren Andersen * An I2C driver for the PCF85063 RTC
4796b7abbSSøren Andersen * Copyright 2014 Rose Technology
5796b7abbSSøren Andersen *
6796b7abbSSøren Andersen * Author: Søren Andersen <san@rosetechnology.dk>
7796b7abbSSøren Andersen * Maintainers: http://www.nslu2-linux.org/
85b3a3adeSAlexandre Belloni *
95b3a3adeSAlexandre Belloni * Copyright (C) 2019 Micro Crystal AG
105b3a3adeSAlexandre Belloni * Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
11796b7abbSSøren Andersen */
128c229ab6SMichael McCormick #include <linux/clk-provider.h>
13796b7abbSSøren Andersen #include <linux/i2c.h>
14796b7abbSSøren Andersen #include <linux/bcd.h>
15796b7abbSSøren Andersen #include <linux/rtc.h>
16796b7abbSSøren Andersen #include <linux/module.h>
1748144c28SRob Herring #include <linux/of.h>
1805cb3a56SAlexandre Belloni #include <linux/pm_wakeirq.h>
19e89b60d0SAlexandre Belloni #include <linux/regmap.h>
20796b7abbSSøren Andersen
210d981f81SChris DeBruin /*
220d981f81SChris DeBruin * Information for this driver was pulled from the following datasheets.
230d981f81SChris DeBruin *
24663bff17SFabio Estevam * https://www.nxp.com/docs/en/data-sheet/PCF85063A.pdf
25663bff17SFabio Estevam * https://www.nxp.com/docs/en/data-sheet/PCF85063TP.pdf
260d981f81SChris DeBruin *
2798c25b80SFabio Estevam * PCF85063A -- Rev. 7 — 30 March 2018
280d981f81SChris DeBruin * PCF85063TP -- Rev. 4 — 6 May 2015
295b3a3adeSAlexandre Belloni *
305b3a3adeSAlexandre Belloni * https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8263-C7_App-Manual.pdf
315b3a3adeSAlexandre Belloni * RV8263 -- Rev. 1.0 — January 2019
320d981f81SChris DeBruin */
330d981f81SChris DeBruin
34796b7abbSSøren Andersen #define PCF85063_REG_CTRL1 0x00 /* status */
35bbb43838SSam Ravnborg #define PCF85063_REG_CTRL1_CAP_SEL BIT(0)
3631d4d33eSJuergen Borleis #define PCF85063_REG_CTRL1_STOP BIT(5)
379f08c9edSPhil Elwell #define PCF85063_REG_CTRL1_EXT_TEST BIT(7)
38796b7abbSSøren Andersen
3905cb3a56SAlexandre Belloni #define PCF85063_REG_CTRL2 0x01
4005cb3a56SAlexandre Belloni #define PCF85063_CTRL2_AF BIT(6)
4105cb3a56SAlexandre Belloni #define PCF85063_CTRL2_AIE BIT(7)
4205cb3a56SAlexandre Belloni
4385370d3dSAlexandre Belloni #define PCF85063_REG_OFFSET 0x02
4485370d3dSAlexandre Belloni #define PCF85063_OFFSET_SIGN_BIT 6 /* 2's complement sign bit */
4585370d3dSAlexandre Belloni #define PCF85063_OFFSET_MODE BIT(7)
4685370d3dSAlexandre Belloni #define PCF85063_OFFSET_STEP0 4340
4785370d3dSAlexandre Belloni #define PCF85063_OFFSET_STEP1 4069
4885370d3dSAlexandre Belloni
498c229ab6SMichael McCormick #define PCF85063_REG_CLKO_F_MASK 0x07 /* frequency mask */
508c229ab6SMichael McCormick #define PCF85063_REG_CLKO_F_32768HZ 0x00
518c229ab6SMichael McCormick #define PCF85063_REG_CLKO_F_OFF 0x07
528c229ab6SMichael McCormick
53fadfd092SAlexandre Belloni #define PCF85063_REG_RAM 0x03
54fadfd092SAlexandre Belloni
55796b7abbSSøren Andersen #define PCF85063_REG_SC 0x04 /* datetime */
566cc4c8b1SJuergen Borleis #define PCF85063_REG_SC_OS 0x80
57796b7abbSSøren Andersen
5805cb3a56SAlexandre Belloni #define PCF85063_REG_ALM_S 0x0b
5905cb3a56SAlexandre Belloni #define PCF85063_AEN BIT(7)
6005cb3a56SAlexandre Belloni
610e2e8777SAlexandre Belloni struct pcf85063_config {
620e2e8777SAlexandre Belloni struct regmap_config regmap;
6305cb3a56SAlexandre Belloni unsigned has_alarms:1;
645b3a3adeSAlexandre Belloni unsigned force_cap_7000:1;
650e2e8777SAlexandre Belloni };
660e2e8777SAlexandre Belloni
67e89b60d0SAlexandre Belloni struct pcf85063 {
68e89b60d0SAlexandre Belloni struct rtc_device *rtc;
69e89b60d0SAlexandre Belloni struct regmap *regmap;
708c229ab6SMichael McCormick #ifdef CONFIG_COMMON_CLK
718c229ab6SMichael McCormick struct clk_hw clkout_hw;
728c229ab6SMichael McCormick #endif
73e89b60d0SAlexandre Belloni };
740d981f81SChris DeBruin
pcf85063_rtc_read_time(struct device * dev,struct rtc_time * tm)75965271dfSAlexandre Belloni static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm)
76796b7abbSSøren Andersen {
77e89b60d0SAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
787b576848SJuergen Borleis int rc;
797b576848SJuergen Borleis u8 regs[7];
80796b7abbSSøren Andersen
817b576848SJuergen Borleis /*
827b576848SJuergen Borleis * while reading, the time/date registers are blocked and not updated
837b576848SJuergen Borleis * anymore until the access is finished. To not lose a second
847b576848SJuergen Borleis * event, the access must be finished within one second. So, read all
857b576848SJuergen Borleis * time/date registers in one turn.
867b576848SJuergen Borleis */
87e89b60d0SAlexandre Belloni rc = regmap_bulk_read(pcf85063->regmap, PCF85063_REG_SC, regs,
88e89b60d0SAlexandre Belloni sizeof(regs));
89e89b60d0SAlexandre Belloni if (rc)
90e89b60d0SAlexandre Belloni return rc;
91796b7abbSSøren Andersen
926cc4c8b1SJuergen Borleis /* if the clock has lost its power it makes no sense to use its time */
936cc4c8b1SJuergen Borleis if (regs[0] & PCF85063_REG_SC_OS) {
94e89b60d0SAlexandre Belloni dev_warn(&pcf85063->rtc->dev, "Power loss detected, invalid time\n");
956cc4c8b1SJuergen Borleis return -EINVAL;
966cc4c8b1SJuergen Borleis }
976cc4c8b1SJuergen Borleis
987b576848SJuergen Borleis tm->tm_sec = bcd2bin(regs[0] & 0x7F);
997b576848SJuergen Borleis tm->tm_min = bcd2bin(regs[1] & 0x7F);
1007b576848SJuergen Borleis tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */
1017b576848SJuergen Borleis tm->tm_mday = bcd2bin(regs[3] & 0x3F);
1027b576848SJuergen Borleis tm->tm_wday = regs[4] & 0x07;
1037b576848SJuergen Borleis tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
1047b576848SJuergen Borleis tm->tm_year = bcd2bin(regs[6]);
105c421ce72SAlexandre Belloni tm->tm_year += 100;
106796b7abbSSøren Andersen
1070a6b8886SAlexandre Belloni return 0;
108796b7abbSSøren Andersen }
109796b7abbSSøren Andersen
pcf85063_rtc_set_time(struct device * dev,struct rtc_time * tm)110965271dfSAlexandre Belloni static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm)
111796b7abbSSøren Andersen {
112e89b60d0SAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
11331d4d33eSJuergen Borleis int rc;
1140d981f81SChris DeBruin u8 regs[7];
115796b7abbSSøren Andersen
11631d4d33eSJuergen Borleis /*
11731d4d33eSJuergen Borleis * to accurately set the time, reset the divider chain and keep it in
11831d4d33eSJuergen Borleis * reset state until all time/date registers are written
11931d4d33eSJuergen Borleis */
120e89b60d0SAlexandre Belloni rc = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1,
1219f08c9edSPhil Elwell PCF85063_REG_CTRL1_EXT_TEST |
122e89b60d0SAlexandre Belloni PCF85063_REG_CTRL1_STOP,
123e89b60d0SAlexandre Belloni PCF85063_REG_CTRL1_STOP);
124e89b60d0SAlexandre Belloni if (rc)
12531d4d33eSJuergen Borleis return rc;
126796b7abbSSøren Andersen
127796b7abbSSøren Andersen /* hours, minutes and seconds */
12831d4d33eSJuergen Borleis regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */
129796b7abbSSøren Andersen
13031d4d33eSJuergen Borleis regs[1] = bin2bcd(tm->tm_min);
13131d4d33eSJuergen Borleis regs[2] = bin2bcd(tm->tm_hour);
132796b7abbSSøren Andersen
133796b7abbSSøren Andersen /* Day of month, 1 - 31 */
13431d4d33eSJuergen Borleis regs[3] = bin2bcd(tm->tm_mday);
135796b7abbSSøren Andersen
136796b7abbSSøren Andersen /* Day, 0 - 6 */
13731d4d33eSJuergen Borleis regs[4] = tm->tm_wday & 0x07;
138796b7abbSSøren Andersen
139796b7abbSSøren Andersen /* month, 1 - 12 */
14031d4d33eSJuergen Borleis regs[5] = bin2bcd(tm->tm_mon + 1);
141796b7abbSSøren Andersen
142796b7abbSSøren Andersen /* year and century */
143c421ce72SAlexandre Belloni regs[6] = bin2bcd(tm->tm_year - 100);
144796b7abbSSøren Andersen
14531d4d33eSJuergen Borleis /* write all registers at once */
146e89b60d0SAlexandre Belloni rc = regmap_bulk_write(pcf85063->regmap, PCF85063_REG_SC,
147e89b60d0SAlexandre Belloni regs, sizeof(regs));
148e89b60d0SAlexandre Belloni if (rc)
14931d4d33eSJuergen Borleis return rc;
150796b7abbSSøren Andersen
1510d981f81SChris DeBruin /*
1520d981f81SChris DeBruin * Write the control register as a separate action since the size of
1530d981f81SChris DeBruin * the register space is different between the PCF85063TP and
1540d981f81SChris DeBruin * PCF85063A devices. The rollover point can not be used.
1550d981f81SChris DeBruin */
156e89b60d0SAlexandre Belloni return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1,
157e89b60d0SAlexandre Belloni PCF85063_REG_CTRL1_STOP, 0);
158796b7abbSSøren Andersen }
159796b7abbSSøren Andersen
pcf85063_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alrm)16005cb3a56SAlexandre Belloni static int pcf85063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
16105cb3a56SAlexandre Belloni {
16205cb3a56SAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
16305cb3a56SAlexandre Belloni u8 buf[4];
16405cb3a56SAlexandre Belloni unsigned int val;
16505cb3a56SAlexandre Belloni int ret;
16605cb3a56SAlexandre Belloni
16705cb3a56SAlexandre Belloni ret = regmap_bulk_read(pcf85063->regmap, PCF85063_REG_ALM_S,
16805cb3a56SAlexandre Belloni buf, sizeof(buf));
16905cb3a56SAlexandre Belloni if (ret)
17005cb3a56SAlexandre Belloni return ret;
17105cb3a56SAlexandre Belloni
172a6ceee26SAlexander Stein alrm->time.tm_sec = bcd2bin(buf[0] & 0x7f);
173a6ceee26SAlexander Stein alrm->time.tm_min = bcd2bin(buf[1] & 0x7f);
174a6ceee26SAlexander Stein alrm->time.tm_hour = bcd2bin(buf[2] & 0x3f);
175a6ceee26SAlexander Stein alrm->time.tm_mday = bcd2bin(buf[3] & 0x3f);
17605cb3a56SAlexandre Belloni
17705cb3a56SAlexandre Belloni ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &val);
17805cb3a56SAlexandre Belloni if (ret)
17905cb3a56SAlexandre Belloni return ret;
18005cb3a56SAlexandre Belloni
18105cb3a56SAlexandre Belloni alrm->enabled = !!(val & PCF85063_CTRL2_AIE);
18205cb3a56SAlexandre Belloni
18305cb3a56SAlexandre Belloni return 0;
18405cb3a56SAlexandre Belloni }
18505cb3a56SAlexandre Belloni
pcf85063_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alrm)18605cb3a56SAlexandre Belloni static int pcf85063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
18705cb3a56SAlexandre Belloni {
18805cb3a56SAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
18905cb3a56SAlexandre Belloni u8 buf[5];
19005cb3a56SAlexandre Belloni int ret;
19105cb3a56SAlexandre Belloni
19205cb3a56SAlexandre Belloni buf[0] = bin2bcd(alrm->time.tm_sec);
19305cb3a56SAlexandre Belloni buf[1] = bin2bcd(alrm->time.tm_min);
19405cb3a56SAlexandre Belloni buf[2] = bin2bcd(alrm->time.tm_hour);
19505cb3a56SAlexandre Belloni buf[3] = bin2bcd(alrm->time.tm_mday);
19605cb3a56SAlexandre Belloni buf[4] = PCF85063_AEN; /* Do not match on week day */
19705cb3a56SAlexandre Belloni
19805cb3a56SAlexandre Belloni ret = regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
19905cb3a56SAlexandre Belloni PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF, 0);
20005cb3a56SAlexandre Belloni if (ret)
20105cb3a56SAlexandre Belloni return ret;
20205cb3a56SAlexandre Belloni
20305cb3a56SAlexandre Belloni ret = regmap_bulk_write(pcf85063->regmap, PCF85063_REG_ALM_S,
20405cb3a56SAlexandre Belloni buf, sizeof(buf));
20505cb3a56SAlexandre Belloni if (ret)
20605cb3a56SAlexandre Belloni return ret;
20705cb3a56SAlexandre Belloni
20805cb3a56SAlexandre Belloni return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
20905cb3a56SAlexandre Belloni PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
21005cb3a56SAlexandre Belloni alrm->enabled ? PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF : PCF85063_CTRL2_AF);
21105cb3a56SAlexandre Belloni }
21205cb3a56SAlexandre Belloni
pcf85063_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)21305cb3a56SAlexandre Belloni static int pcf85063_rtc_alarm_irq_enable(struct device *dev,
21405cb3a56SAlexandre Belloni unsigned int enabled)
21505cb3a56SAlexandre Belloni {
21605cb3a56SAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
21705cb3a56SAlexandre Belloni
21805cb3a56SAlexandre Belloni return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
21905cb3a56SAlexandre Belloni PCF85063_CTRL2_AIE,
22005cb3a56SAlexandre Belloni enabled ? PCF85063_CTRL2_AIE : 0);
22105cb3a56SAlexandre Belloni }
22205cb3a56SAlexandre Belloni
pcf85063_rtc_handle_irq(int irq,void * dev_id)22305cb3a56SAlexandre Belloni static irqreturn_t pcf85063_rtc_handle_irq(int irq, void *dev_id)
22405cb3a56SAlexandre Belloni {
22505cb3a56SAlexandre Belloni struct pcf85063 *pcf85063 = dev_id;
22605cb3a56SAlexandre Belloni unsigned int val;
22705cb3a56SAlexandre Belloni int err;
22805cb3a56SAlexandre Belloni
22905cb3a56SAlexandre Belloni err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &val);
23005cb3a56SAlexandre Belloni if (err)
23105cb3a56SAlexandre Belloni return IRQ_NONE;
23205cb3a56SAlexandre Belloni
23305cb3a56SAlexandre Belloni if (val & PCF85063_CTRL2_AF) {
23405cb3a56SAlexandre Belloni rtc_update_irq(pcf85063->rtc, 1, RTC_IRQF | RTC_AF);
23505cb3a56SAlexandre Belloni regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
23605cb3a56SAlexandre Belloni PCF85063_CTRL2_AIE | PCF85063_CTRL2_AF,
23705cb3a56SAlexandre Belloni 0);
23805cb3a56SAlexandre Belloni return IRQ_HANDLED;
23905cb3a56SAlexandre Belloni }
24005cb3a56SAlexandre Belloni
24105cb3a56SAlexandre Belloni return IRQ_NONE;
24205cb3a56SAlexandre Belloni }
24305cb3a56SAlexandre Belloni
pcf85063_read_offset(struct device * dev,long * offset)24485370d3dSAlexandre Belloni static int pcf85063_read_offset(struct device *dev, long *offset)
24585370d3dSAlexandre Belloni {
24685370d3dSAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
24785370d3dSAlexandre Belloni long val;
24885370d3dSAlexandre Belloni u32 reg;
24985370d3dSAlexandre Belloni int ret;
25085370d3dSAlexandre Belloni
25185370d3dSAlexandre Belloni ret = regmap_read(pcf85063->regmap, PCF85063_REG_OFFSET, ®);
25285370d3dSAlexandre Belloni if (ret < 0)
25385370d3dSAlexandre Belloni return ret;
25485370d3dSAlexandre Belloni
25585370d3dSAlexandre Belloni val = sign_extend32(reg & ~PCF85063_OFFSET_MODE,
25685370d3dSAlexandre Belloni PCF85063_OFFSET_SIGN_BIT);
25785370d3dSAlexandre Belloni
25885370d3dSAlexandre Belloni if (reg & PCF85063_OFFSET_MODE)
25985370d3dSAlexandre Belloni *offset = val * PCF85063_OFFSET_STEP1;
26085370d3dSAlexandre Belloni else
26185370d3dSAlexandre Belloni *offset = val * PCF85063_OFFSET_STEP0;
26285370d3dSAlexandre Belloni
26385370d3dSAlexandre Belloni return 0;
26485370d3dSAlexandre Belloni }
26585370d3dSAlexandre Belloni
pcf85063_set_offset(struct device * dev,long offset)26685370d3dSAlexandre Belloni static int pcf85063_set_offset(struct device *dev, long offset)
26785370d3dSAlexandre Belloni {
26885370d3dSAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
26985370d3dSAlexandre Belloni s8 mode0, mode1, reg;
27085370d3dSAlexandre Belloni unsigned int error0, error1;
27185370d3dSAlexandre Belloni
27285370d3dSAlexandre Belloni if (offset > PCF85063_OFFSET_STEP0 * 63)
27385370d3dSAlexandre Belloni return -ERANGE;
27485370d3dSAlexandre Belloni if (offset < PCF85063_OFFSET_STEP0 * -64)
27585370d3dSAlexandre Belloni return -ERANGE;
27685370d3dSAlexandre Belloni
27785370d3dSAlexandre Belloni mode0 = DIV_ROUND_CLOSEST(offset, PCF85063_OFFSET_STEP0);
27885370d3dSAlexandre Belloni mode1 = DIV_ROUND_CLOSEST(offset, PCF85063_OFFSET_STEP1);
27985370d3dSAlexandre Belloni
28085370d3dSAlexandre Belloni error0 = abs(offset - (mode0 * PCF85063_OFFSET_STEP0));
28185370d3dSAlexandre Belloni error1 = abs(offset - (mode1 * PCF85063_OFFSET_STEP1));
28285370d3dSAlexandre Belloni if (mode1 > 63 || mode1 < -64 || error0 < error1)
28385370d3dSAlexandre Belloni reg = mode0 & ~PCF85063_OFFSET_MODE;
28485370d3dSAlexandre Belloni else
28585370d3dSAlexandre Belloni reg = mode1 | PCF85063_OFFSET_MODE;
28685370d3dSAlexandre Belloni
28785370d3dSAlexandre Belloni return regmap_write(pcf85063->regmap, PCF85063_REG_OFFSET, reg);
28885370d3dSAlexandre Belloni }
28985370d3dSAlexandre Belloni
pcf85063_ioctl(struct device * dev,unsigned int cmd,unsigned long arg)29027ff836dSAlexandre Belloni static int pcf85063_ioctl(struct device *dev, unsigned int cmd,
29127ff836dSAlexandre Belloni unsigned long arg)
29227ff836dSAlexandre Belloni {
29327ff836dSAlexandre Belloni struct pcf85063 *pcf85063 = dev_get_drvdata(dev);
29427ff836dSAlexandre Belloni int status, ret = 0;
29527ff836dSAlexandre Belloni
29627ff836dSAlexandre Belloni switch (cmd) {
29727ff836dSAlexandre Belloni case RTC_VL_READ:
29827ff836dSAlexandre Belloni ret = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &status);
29927ff836dSAlexandre Belloni if (ret < 0)
30027ff836dSAlexandre Belloni return ret;
30127ff836dSAlexandre Belloni
30272e4ee63SAlexandre Belloni status = (status & PCF85063_REG_SC_OS) ? RTC_VL_DATA_INVALID : 0;
30327ff836dSAlexandre Belloni
304f86dc5bdSAlexandre Belloni return put_user(status, (unsigned int __user *)arg);
30527ff836dSAlexandre Belloni
30627ff836dSAlexandre Belloni default:
30727ff836dSAlexandre Belloni return -ENOIOCTLCMD;
30827ff836dSAlexandre Belloni }
30927ff836dSAlexandre Belloni }
31027ff836dSAlexandre Belloni
311796b7abbSSøren Andersen static const struct rtc_class_ops pcf85063_rtc_ops = {
312796b7abbSSøren Andersen .read_time = pcf85063_rtc_read_time,
31385370d3dSAlexandre Belloni .set_time = pcf85063_rtc_set_time,
31485370d3dSAlexandre Belloni .read_offset = pcf85063_read_offset,
31585370d3dSAlexandre Belloni .set_offset = pcf85063_set_offset,
31605cb3a56SAlexandre Belloni .read_alarm = pcf85063_rtc_read_alarm,
31705cb3a56SAlexandre Belloni .set_alarm = pcf85063_rtc_set_alarm,
31805cb3a56SAlexandre Belloni .alarm_irq_enable = pcf85063_rtc_alarm_irq_enable,
31927ff836dSAlexandre Belloni .ioctl = pcf85063_ioctl,
32005cb3a56SAlexandre Belloni };
32105cb3a56SAlexandre Belloni
pcf85063_nvmem_read(void * priv,unsigned int offset,void * val,size_t bytes)322fadfd092SAlexandre Belloni static int pcf85063_nvmem_read(void *priv, unsigned int offset,
323fadfd092SAlexandre Belloni void *val, size_t bytes)
324fadfd092SAlexandre Belloni {
325*9adefa7bSOleksij Rempel unsigned int tmp;
326*9adefa7bSOleksij Rempel int ret;
327*9adefa7bSOleksij Rempel
328*9adefa7bSOleksij Rempel ret = regmap_read(priv, PCF85063_REG_RAM, &tmp);
329*9adefa7bSOleksij Rempel if (ret < 0)
330*9adefa7bSOleksij Rempel return ret;
331*9adefa7bSOleksij Rempel
332*9adefa7bSOleksij Rempel *(u8 *)val = tmp;
333*9adefa7bSOleksij Rempel
334*9adefa7bSOleksij Rempel return 0;
335fadfd092SAlexandre Belloni }
336fadfd092SAlexandre Belloni
pcf85063_nvmem_write(void * priv,unsigned int offset,void * val,size_t bytes)337fadfd092SAlexandre Belloni static int pcf85063_nvmem_write(void *priv, unsigned int offset,
338fadfd092SAlexandre Belloni void *val, size_t bytes)
339fadfd092SAlexandre Belloni {
340fadfd092SAlexandre Belloni return regmap_write(priv, PCF85063_REG_RAM, *(u8 *)val);
341fadfd092SAlexandre Belloni }
342fadfd092SAlexandre Belloni
pcf85063_load_capacitance(struct pcf85063 * pcf85063,const struct device_node * np,unsigned int force_cap)343e89b60d0SAlexandre Belloni static int pcf85063_load_capacitance(struct pcf85063 *pcf85063,
3445b3a3adeSAlexandre Belloni const struct device_node *np,
3455b3a3adeSAlexandre Belloni unsigned int force_cap)
346bbb43838SSam Ravnborg {
347e89b60d0SAlexandre Belloni u32 load = 7000;
348e89b60d0SAlexandre Belloni u8 reg = 0;
349bbb43838SSam Ravnborg
3505b3a3adeSAlexandre Belloni if (force_cap)
3515b3a3adeSAlexandre Belloni load = force_cap;
3525b3a3adeSAlexandre Belloni else
353e89b60d0SAlexandre Belloni of_property_read_u32(np, "quartz-load-femtofarads", &load);
3545b3a3adeSAlexandre Belloni
355bbb43838SSam Ravnborg switch (load) {
356bbb43838SSam Ravnborg default:
357e89b60d0SAlexandre Belloni dev_warn(&pcf85063->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
358bbb43838SSam Ravnborg load);
359df561f66SGustavo A. R. Silva fallthrough;
360bbb43838SSam Ravnborg case 7000:
361bbb43838SSam Ravnborg break;
362bbb43838SSam Ravnborg case 12500:
363e89b60d0SAlexandre Belloni reg = PCF85063_REG_CTRL1_CAP_SEL;
364bbb43838SSam Ravnborg break;
365bbb43838SSam Ravnborg }
366bbb43838SSam Ravnborg
367e89b60d0SAlexandre Belloni return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL1,
368e89b60d0SAlexandre Belloni PCF85063_REG_CTRL1_CAP_SEL, reg);
369bbb43838SSam Ravnborg }
370bbb43838SSam Ravnborg
3718c229ab6SMichael McCormick #ifdef CONFIG_COMMON_CLK
3728c229ab6SMichael McCormick /*
3738c229ab6SMichael McCormick * Handling of the clkout
3748c229ab6SMichael McCormick */
3758c229ab6SMichael McCormick
3768c229ab6SMichael McCormick #define clkout_hw_to_pcf85063(_hw) container_of(_hw, struct pcf85063, clkout_hw)
3778c229ab6SMichael McCormick
3788c229ab6SMichael McCormick static int clkout_rates[] = {
3798c229ab6SMichael McCormick 32768,
3808c229ab6SMichael McCormick 16384,
3818c229ab6SMichael McCormick 8192,
3828c229ab6SMichael McCormick 4096,
3838c229ab6SMichael McCormick 2048,
3848c229ab6SMichael McCormick 1024,
3858c229ab6SMichael McCormick 1,
3868c229ab6SMichael McCormick 0
3878c229ab6SMichael McCormick };
3888c229ab6SMichael McCormick
pcf85063_clkout_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)3898c229ab6SMichael McCormick static unsigned long pcf85063_clkout_recalc_rate(struct clk_hw *hw,
3908c229ab6SMichael McCormick unsigned long parent_rate)
3918c229ab6SMichael McCormick {
3928c229ab6SMichael McCormick struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw);
3938c229ab6SMichael McCormick unsigned int buf;
3948c229ab6SMichael McCormick int ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &buf);
3958c229ab6SMichael McCormick
3968c229ab6SMichael McCormick if (ret < 0)
3978c229ab6SMichael McCormick return 0;
3988c229ab6SMichael McCormick
3998c229ab6SMichael McCormick buf &= PCF85063_REG_CLKO_F_MASK;
4008c229ab6SMichael McCormick return clkout_rates[buf];
4018c229ab6SMichael McCormick }
4028c229ab6SMichael McCormick
pcf85063_clkout_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)4038c229ab6SMichael McCormick static long pcf85063_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
4048c229ab6SMichael McCormick unsigned long *prate)
4058c229ab6SMichael McCormick {
4068c229ab6SMichael McCormick int i;
4078c229ab6SMichael McCormick
4088c229ab6SMichael McCormick for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
4098c229ab6SMichael McCormick if (clkout_rates[i] <= rate)
4108c229ab6SMichael McCormick return clkout_rates[i];
4118c229ab6SMichael McCormick
4128c229ab6SMichael McCormick return 0;
4138c229ab6SMichael McCormick }
4148c229ab6SMichael McCormick
pcf85063_clkout_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)4158c229ab6SMichael McCormick static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
4168c229ab6SMichael McCormick unsigned long parent_rate)
4178c229ab6SMichael McCormick {
4188c229ab6SMichael McCormick struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw);
4198c229ab6SMichael McCormick int i;
4208c229ab6SMichael McCormick
4218c229ab6SMichael McCormick for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
4228c229ab6SMichael McCormick if (clkout_rates[i] == rate)
4238c229ab6SMichael McCormick return regmap_update_bits(pcf85063->regmap,
4248c229ab6SMichael McCormick PCF85063_REG_CTRL2,
4258c229ab6SMichael McCormick PCF85063_REG_CLKO_F_MASK, i);
4268c229ab6SMichael McCormick
4278c229ab6SMichael McCormick return -EINVAL;
4288c229ab6SMichael McCormick }
4298c229ab6SMichael McCormick
pcf85063_clkout_control(struct clk_hw * hw,bool enable)4308c229ab6SMichael McCormick static int pcf85063_clkout_control(struct clk_hw *hw, bool enable)
4318c229ab6SMichael McCormick {
4328c229ab6SMichael McCormick struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw);
4338c229ab6SMichael McCormick unsigned int buf;
4348c229ab6SMichael McCormick int ret;
4358c229ab6SMichael McCormick
436c2d12e85SAlexandre Belloni ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &buf);
4378c229ab6SMichael McCormick if (ret < 0)
4388c229ab6SMichael McCormick return ret;
4398c229ab6SMichael McCormick buf &= PCF85063_REG_CLKO_F_MASK;
4408c229ab6SMichael McCormick
4418c229ab6SMichael McCormick if (enable) {
4428c229ab6SMichael McCormick if (buf == PCF85063_REG_CLKO_F_OFF)
4438c229ab6SMichael McCormick buf = PCF85063_REG_CLKO_F_32768HZ;
4448c229ab6SMichael McCormick else
4458c229ab6SMichael McCormick return 0;
4468c229ab6SMichael McCormick } else {
4478c229ab6SMichael McCormick if (buf != PCF85063_REG_CLKO_F_OFF)
4488c229ab6SMichael McCormick buf = PCF85063_REG_CLKO_F_OFF;
4498c229ab6SMichael McCormick else
4508c229ab6SMichael McCormick return 0;
4518c229ab6SMichael McCormick }
4528c229ab6SMichael McCormick
4538c229ab6SMichael McCormick return regmap_update_bits(pcf85063->regmap, PCF85063_REG_CTRL2,
4548c229ab6SMichael McCormick PCF85063_REG_CLKO_F_MASK, buf);
4558c229ab6SMichael McCormick }
4568c229ab6SMichael McCormick
pcf85063_clkout_prepare(struct clk_hw * hw)4578c229ab6SMichael McCormick static int pcf85063_clkout_prepare(struct clk_hw *hw)
4588c229ab6SMichael McCormick {
4598c229ab6SMichael McCormick return pcf85063_clkout_control(hw, 1);
4608c229ab6SMichael McCormick }
4618c229ab6SMichael McCormick
pcf85063_clkout_unprepare(struct clk_hw * hw)4628c229ab6SMichael McCormick static void pcf85063_clkout_unprepare(struct clk_hw *hw)
4638c229ab6SMichael McCormick {
4648c229ab6SMichael McCormick pcf85063_clkout_control(hw, 0);
4658c229ab6SMichael McCormick }
4668c229ab6SMichael McCormick
pcf85063_clkout_is_prepared(struct clk_hw * hw)4678c229ab6SMichael McCormick static int pcf85063_clkout_is_prepared(struct clk_hw *hw)
4688c229ab6SMichael McCormick {
4698c229ab6SMichael McCormick struct pcf85063 *pcf85063 = clkout_hw_to_pcf85063(hw);
4708c229ab6SMichael McCormick unsigned int buf;
4718c229ab6SMichael McCormick int ret = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL2, &buf);
4728c229ab6SMichael McCormick
4738c229ab6SMichael McCormick if (ret < 0)
4748c229ab6SMichael McCormick return 0;
4758c229ab6SMichael McCormick
4768c229ab6SMichael McCormick return (buf & PCF85063_REG_CLKO_F_MASK) != PCF85063_REG_CLKO_F_OFF;
4778c229ab6SMichael McCormick }
4788c229ab6SMichael McCormick
4798c229ab6SMichael McCormick static const struct clk_ops pcf85063_clkout_ops = {
4808c229ab6SMichael McCormick .prepare = pcf85063_clkout_prepare,
4818c229ab6SMichael McCormick .unprepare = pcf85063_clkout_unprepare,
4828c229ab6SMichael McCormick .is_prepared = pcf85063_clkout_is_prepared,
4838c229ab6SMichael McCormick .recalc_rate = pcf85063_clkout_recalc_rate,
4848c229ab6SMichael McCormick .round_rate = pcf85063_clkout_round_rate,
4858c229ab6SMichael McCormick .set_rate = pcf85063_clkout_set_rate,
4868c229ab6SMichael McCormick };
4878c229ab6SMichael McCormick
pcf85063_clkout_register_clk(struct pcf85063 * pcf85063)4888c229ab6SMichael McCormick static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
4898c229ab6SMichael McCormick {
4908c229ab6SMichael McCormick struct clk *clk;
4918c229ab6SMichael McCormick struct clk_init_data init;
49203531606SFrancois Gervais struct device_node *node = pcf85063->rtc->dev.parent->of_node;
4934c8a7b80SAlexander Stein struct device_node *fixed_clock;
4944c8a7b80SAlexander Stein
4954c8a7b80SAlexander Stein fixed_clock = of_get_child_by_name(node, "clock");
4964c8a7b80SAlexander Stein if (fixed_clock) {
4974c8a7b80SAlexander Stein /*
4984c8a7b80SAlexander Stein * skip registering square wave clock when a fixed
4994c8a7b80SAlexander Stein * clock has been registered. The fixed clock is
5004c8a7b80SAlexander Stein * registered automatically when being referenced.
5014c8a7b80SAlexander Stein */
5024c8a7b80SAlexander Stein of_node_put(fixed_clock);
5034c8a7b80SAlexander Stein return NULL;
5044c8a7b80SAlexander Stein }
5058c229ab6SMichael McCormick
5068c229ab6SMichael McCormick init.name = "pcf85063-clkout";
5078c229ab6SMichael McCormick init.ops = &pcf85063_clkout_ops;
5088c229ab6SMichael McCormick init.flags = 0;
5098c229ab6SMichael McCormick init.parent_names = NULL;
5108c229ab6SMichael McCormick init.num_parents = 0;
5118c229ab6SMichael McCormick pcf85063->clkout_hw.init = &init;
5128c229ab6SMichael McCormick
5138c229ab6SMichael McCormick /* optional override of the clockname */
51403531606SFrancois Gervais of_property_read_string(node, "clock-output-names", &init.name);
5158c229ab6SMichael McCormick
5168c229ab6SMichael McCormick /* register the clock */
5178c229ab6SMichael McCormick clk = devm_clk_register(&pcf85063->rtc->dev, &pcf85063->clkout_hw);
5188c229ab6SMichael McCormick
5198c229ab6SMichael McCormick if (!IS_ERR(clk))
52003531606SFrancois Gervais of_clk_add_provider(node, of_clk_src_simple_get, clk);
5218c229ab6SMichael McCormick
5228c229ab6SMichael McCormick return clk;
5238c229ab6SMichael McCormick }
5248c229ab6SMichael McCormick #endif
5258c229ab6SMichael McCormick
5265789837cSBiju Das static const struct pcf85063_config config_pcf85063 = {
5275789837cSBiju Das .regmap = {
5285789837cSBiju Das .reg_bits = 8,
5295789837cSBiju Das .val_bits = 8,
5305789837cSBiju Das .max_register = 0x0a,
5315789837cSBiju Das },
5321c1b3098SMarc Ferland };
5331c1b3098SMarc Ferland
5345789837cSBiju Das static const struct pcf85063_config config_pcf85063tp = {
5350e2e8777SAlexandre Belloni .regmap = {
5360e2e8777SAlexandre Belloni .reg_bits = 8,
5370e2e8777SAlexandre Belloni .val_bits = 8,
5380e2e8777SAlexandre Belloni .max_register = 0x0a,
5390e2e8777SAlexandre Belloni },
5405789837cSBiju Das };
5415789837cSBiju Das
5425789837cSBiju Das static const struct pcf85063_config config_pcf85063a = {
5431c1b3098SMarc Ferland .regmap = {
5441c1b3098SMarc Ferland .reg_bits = 8,
5451c1b3098SMarc Ferland .val_bits = 8,
5461c1b3098SMarc Ferland .max_register = 0x11,
5471c1b3098SMarc Ferland },
5481c1b3098SMarc Ferland .has_alarms = 1,
5495789837cSBiju Das };
5505789837cSBiju Das
5515789837cSBiju Das static const struct pcf85063_config config_rv8263 = {
5521c1b3098SMarc Ferland .regmap = {
5531c1b3098SMarc Ferland .reg_bits = 8,
5541c1b3098SMarc Ferland .val_bits = 8,
5551c1b3098SMarc Ferland .max_register = 0x11,
5561c1b3098SMarc Ferland },
5571c1b3098SMarc Ferland .has_alarms = 1,
5581c1b3098SMarc Ferland .force_cap_7000 = 1,
559e89b60d0SAlexandre Belloni };
560e89b60d0SAlexandre Belloni
pcf85063_probe(struct i2c_client * client)5610f21700aSAlexandre Belloni static int pcf85063_probe(struct i2c_client *client)
562796b7abbSSøren Andersen {
563e89b60d0SAlexandre Belloni struct pcf85063 *pcf85063;
564e89b60d0SAlexandre Belloni unsigned int tmp;
565c18b4c52SMirza Krak int err;
5661c1b3098SMarc Ferland const struct pcf85063_config *config;
567fadfd092SAlexandre Belloni struct nvmem_config nvmem_cfg = {
568fadfd092SAlexandre Belloni .name = "pcf85063_nvram",
569fadfd092SAlexandre Belloni .reg_read = pcf85063_nvmem_read,
570fadfd092SAlexandre Belloni .reg_write = pcf85063_nvmem_write,
571fadfd092SAlexandre Belloni .type = NVMEM_TYPE_BATTERY_BACKED,
572fadfd092SAlexandre Belloni .size = 1,
573fadfd092SAlexandre Belloni };
574796b7abbSSøren Andersen
575796b7abbSSøren Andersen dev_dbg(&client->dev, "%s\n", __func__);
576796b7abbSSøren Andersen
577e89b60d0SAlexandre Belloni pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063),
578e89b60d0SAlexandre Belloni GFP_KERNEL);
579e89b60d0SAlexandre Belloni if (!pcf85063)
580e89b60d0SAlexandre Belloni return -ENOMEM;
581e89b60d0SAlexandre Belloni
58268c624f8SBiju Das config = i2c_get_match_data(client);
5831c1b3098SMarc Ferland if (!config)
5841c1b3098SMarc Ferland return -ENODEV;
5850e2e8777SAlexandre Belloni
5860e2e8777SAlexandre Belloni pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap);
587e89b60d0SAlexandre Belloni if (IS_ERR(pcf85063->regmap))
588e89b60d0SAlexandre Belloni return PTR_ERR(pcf85063->regmap);
589e89b60d0SAlexandre Belloni
590e89b60d0SAlexandre Belloni i2c_set_clientdata(client, pcf85063);
591e89b60d0SAlexandre Belloni
592e89b60d0SAlexandre Belloni err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp);
593e89b60d0SAlexandre Belloni if (err) {
594c18b4c52SMirza Krak dev_err(&client->dev, "RTC chip is not present\n");
595c18b4c52SMirza Krak return err;
596c18b4c52SMirza Krak }
597c18b4c52SMirza Krak
598e89b60d0SAlexandre Belloni pcf85063->rtc = devm_rtc_allocate_device(&client->dev);
599e89b60d0SAlexandre Belloni if (IS_ERR(pcf85063->rtc))
600e89b60d0SAlexandre Belloni return PTR_ERR(pcf85063->rtc);
601e89b60d0SAlexandre Belloni
6025b3a3adeSAlexandre Belloni err = pcf85063_load_capacitance(pcf85063, client->dev.of_node,
6035b3a3adeSAlexandre Belloni config->force_cap_7000 ? 7000 : 0);
604bbb43838SSam Ravnborg if (err < 0)
605bbb43838SSam Ravnborg dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
606bbb43838SSam Ravnborg err);
607bbb43838SSam Ravnborg
608e89b60d0SAlexandre Belloni pcf85063->rtc->ops = &pcf85063_rtc_ops;
609e89b60d0SAlexandre Belloni pcf85063->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
610e89b60d0SAlexandre Belloni pcf85063->rtc->range_max = RTC_TIMESTAMP_END_2099;
611a9f2d5bbSAlexandre Belloni set_bit(RTC_FEATURE_ALARM_RES_2S, pcf85063->rtc->features);
61211316c24SAlexandre Belloni clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features);
613d4eaffe2SAlexandre Belloni clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
61405cb3a56SAlexandre Belloni
61505cb3a56SAlexandre Belloni if (config->has_alarms && client->irq > 0) {
6167e815272SAlexandre Belloni unsigned long irqflags = IRQF_TRIGGER_LOW;
6177e815272SAlexandre Belloni
6187e815272SAlexandre Belloni if (dev_fwnode(&client->dev))
6197e815272SAlexandre Belloni irqflags = 0;
6207e815272SAlexandre Belloni
62105cb3a56SAlexandre Belloni err = devm_request_threaded_irq(&client->dev, client->irq,
62205cb3a56SAlexandre Belloni NULL, pcf85063_rtc_handle_irq,
6237e815272SAlexandre Belloni irqflags | IRQF_ONESHOT,
62405cb3a56SAlexandre Belloni "pcf85063", pcf85063);
62505cb3a56SAlexandre Belloni if (err) {
62605cb3a56SAlexandre Belloni dev_warn(&pcf85063->rtc->dev,
62705cb3a56SAlexandre Belloni "unable to request IRQ, alarms disabled\n");
62805cb3a56SAlexandre Belloni } else {
629d4eaffe2SAlexandre Belloni set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
63005cb3a56SAlexandre Belloni device_init_wakeup(&client->dev, true);
63105cb3a56SAlexandre Belloni err = dev_pm_set_wake_irq(&client->dev, client->irq);
63205cb3a56SAlexandre Belloni if (err)
63305cb3a56SAlexandre Belloni dev_err(&pcf85063->rtc->dev,
63405cb3a56SAlexandre Belloni "failed to enable irq wake\n");
63505cb3a56SAlexandre Belloni }
63605cb3a56SAlexandre Belloni }
637796b7abbSSøren Andersen
638fadfd092SAlexandre Belloni nvmem_cfg.priv = pcf85063->regmap;
6393a905c2dSBartosz Golaszewski devm_rtc_nvmem_register(pcf85063->rtc, &nvmem_cfg);
640fadfd092SAlexandre Belloni
6418c229ab6SMichael McCormick #ifdef CONFIG_COMMON_CLK
6428c229ab6SMichael McCormick /* register clk in common clk framework */
6438c229ab6SMichael McCormick pcf85063_clkout_register_clk(pcf85063);
6448c229ab6SMichael McCormick #endif
6458c229ab6SMichael McCormick
646fdcfd854SBartosz Golaszewski return devm_rtc_register_device(pcf85063->rtc);
647796b7abbSSøren Andersen }
648796b7abbSSøren Andersen
6491c1b3098SMarc Ferland static const struct i2c_device_id pcf85063_ids[] = {
6505789837cSBiju Das { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
6515789837cSBiju Das { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 },
6525789837cSBiju Das { "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp },
6535789837cSBiju Das { "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
6545789837cSBiju Das { "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 },
6551c1b3098SMarc Ferland {}
6561c1b3098SMarc Ferland };
6571c1b3098SMarc Ferland MODULE_DEVICE_TABLE(i2c, pcf85063_ids);
6581c1b3098SMarc Ferland
659796b7abbSSøren Andersen #ifdef CONFIG_OF
660796b7abbSSøren Andersen static const struct of_device_id pcf85063_of_match[] = {
6615789837cSBiju Das { .compatible = "nxp,pca85073a", .data = &config_pcf85063a },
6625789837cSBiju Das { .compatible = "nxp,pcf85063", .data = &config_pcf85063 },
6635789837cSBiju Das { .compatible = "nxp,pcf85063tp", .data = &config_pcf85063tp },
6645789837cSBiju Das { .compatible = "nxp,pcf85063a", .data = &config_pcf85063a },
6655789837cSBiju Das { .compatible = "microcrystal,rv8263", .data = &config_rv8263 },
666796b7abbSSøren Andersen {}
667796b7abbSSøren Andersen };
668796b7abbSSøren Andersen MODULE_DEVICE_TABLE(of, pcf85063_of_match);
669796b7abbSSøren Andersen #endif
670796b7abbSSøren Andersen
671796b7abbSSøren Andersen static struct i2c_driver pcf85063_driver = {
672796b7abbSSøren Andersen .driver = {
673796b7abbSSøren Andersen .name = "rtc-pcf85063",
674796b7abbSSøren Andersen .of_match_table = of_match_ptr(pcf85063_of_match),
675796b7abbSSøren Andersen },
67631b0cecbSUwe Kleine-König .probe = pcf85063_probe,
6771c1b3098SMarc Ferland .id_table = pcf85063_ids,
678796b7abbSSøren Andersen };
679796b7abbSSøren Andersen
680796b7abbSSøren Andersen module_i2c_driver(pcf85063_driver);
681796b7abbSSøren Andersen
682796b7abbSSøren Andersen MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>");
683796b7abbSSøren Andersen MODULE_DESCRIPTION("PCF85063 RTC driver");
684796b7abbSSøren Andersen MODULE_LICENSE("GPL");
685