Blame view
drivers/rtc/rtc-pcf85063.c
5.74 KB
796b7abb3
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * An I2C driver for the PCF85063 RTC * Copyright 2014 Rose Technology * * Author: Søren Andersen <san@rosetechnology.dk> * Maintainers: http://www.nslu2-linux.org/ * * based on the other drivers in this same directory. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/i2c.h> #include <linux/bcd.h> #include <linux/rtc.h> #include <linux/module.h> |
0d981f81e
|
18 19 20 21 22 23 24 25 26 |
/* * Information for this driver was pulled from the following datasheets. * * http://www.nxp.com/documents/data_sheet/PCF85063A.pdf * http://www.nxp.com/documents/data_sheet/PCF85063TP.pdf * * PCF85063A -- Rev. 6 — 18 November 2015 * PCF85063TP -- Rev. 4 — 6 May 2015 */ |
796b7abb3
|
27 |
#define PCF85063_REG_CTRL1 0x00 /* status */ |
31d4d33ef
|
28 |
#define PCF85063_REG_CTRL1_STOP BIT(5) |
796b7abb3
|
29 30 31 |
#define PCF85063_REG_CTRL2 0x01 #define PCF85063_REG_SC 0x04 /* datetime */ |
6cc4c8b1e
|
32 |
#define PCF85063_REG_SC_OS 0x80 |
796b7abb3
|
33 34 35 36 37 38 |
#define PCF85063_REG_MN 0x05 #define PCF85063_REG_HR 0x06 #define PCF85063_REG_DM 0x07 #define PCF85063_REG_DW 0x08 #define PCF85063_REG_MO 0x09 #define PCF85063_REG_YR 0x0A |
796b7abb3
|
39 |
static struct i2c_driver pcf85063_driver; |
31d4d33ef
|
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) { s32 ret; ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); if (ret < 0) { dev_err(&client->dev, "Failing to stop the clock "); return -EIO; } /* stop the clock */ ret |= PCF85063_REG_CTRL1_STOP; ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret); if (ret < 0) { dev_err(&client->dev, "Failing to stop the clock "); return -EIO; } *ctrl1 = ret; return 0; } |
0d981f81e
|
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1) { s32 ret; /* start the clock */ ctrl1 &= PCF85063_REG_CTRL1_STOP; ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1); if (ret < 0) { dev_err(&client->dev, "Failing to start the clock "); return -EIO; } return 0; } |
796b7abb3
|
81 82 |
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) { |
7b5768486
|
83 |
int rc; |
7b5768486
|
84 85 86 87 88 89 90 91 92 93 94 95 96 |
u8 regs[7]; /* * while reading, the time/date registers are blocked and not updated * anymore until the access is finished. To not lose a second * event, the access must be finished within one second. So, read all * time/date registers in one turn. */ rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC, sizeof(regs), regs); if (rc != sizeof(regs)) { dev_err(&client->dev, "date/time register read error "); |
796b7abb3
|
97 98 |
return -EIO; } |
6cc4c8b1e
|
99 100 101 102 103 104 |
/* if the clock has lost its power it makes no sense to use its time */ if (regs[0] & PCF85063_REG_SC_OS) { dev_warn(&client->dev, "Power loss detected, invalid time "); return -EINVAL; } |
7b5768486
|
105 106 107 108 109 110 111 |
tm->tm_sec = bcd2bin(regs[0] & 0x7F); tm->tm_min = bcd2bin(regs[1] & 0x7F); tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */ tm->tm_mday = bcd2bin(regs[3] & 0x3F); tm->tm_wday = regs[4] & 0x07; tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */ tm->tm_year = bcd2bin(regs[6]); |
c421ce726
|
112 |
tm->tm_year += 100; |
796b7abb3
|
113 |
|
5413eaba5
|
114 |
return rtc_valid_tm(tm); |
796b7abb3
|
115 116 117 118 |
} static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) { |
31d4d33ef
|
119 |
int rc; |
0d981f81e
|
120 121 |
u8 regs[7]; u8 ctrl1; |
796b7abb3
|
122 |
|
c421ce726
|
123 124 |
if ((tm->tm_year < 100) || (tm->tm_year > 199)) return -EINVAL; |
31d4d33ef
|
125 126 127 128 |
/* * to accurately set the time, reset the divider chain and keep it in * reset state until all time/date registers are written */ |
0d981f81e
|
129 |
rc = pcf85063_stop_clock(client, &ctrl1); |
31d4d33ef
|
130 131 |
if (rc != 0) return rc; |
796b7abb3
|
132 133 |
/* hours, minutes and seconds */ |
31d4d33ef
|
134 |
regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */ |
796b7abb3
|
135 |
|
31d4d33ef
|
136 137 |
regs[1] = bin2bcd(tm->tm_min); regs[2] = bin2bcd(tm->tm_hour); |
796b7abb3
|
138 139 |
/* Day of month, 1 - 31 */ |
31d4d33ef
|
140 |
regs[3] = bin2bcd(tm->tm_mday); |
796b7abb3
|
141 142 |
/* Day, 0 - 6 */ |
31d4d33ef
|
143 |
regs[4] = tm->tm_wday & 0x07; |
796b7abb3
|
144 145 |
/* month, 1 - 12 */ |
31d4d33ef
|
146 |
regs[5] = bin2bcd(tm->tm_mon + 1); |
796b7abb3
|
147 148 |
/* year and century */ |
c421ce726
|
149 |
regs[6] = bin2bcd(tm->tm_year - 100); |
31d4d33ef
|
150 |
|
31d4d33ef
|
151 152 153 154 155 156 157 |
/* write all registers at once */ rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC, sizeof(regs), regs); if (rc < 0) { dev_err(&client->dev, "date/time register write error "); return rc; |
796b7abb3
|
158 |
} |
0d981f81e
|
159 160 161 162 163 164 165 166 |
/* * Write the control register as a separate action since the size of * the register space is different between the PCF85063TP and * PCF85063A devices. The rollover point can not be used. */ rc = pcf85063_start_clock(client, ctrl1); if (rc != 0) return rc; |
796b7abb3
|
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
return 0; } static int pcf85063_rtc_read_time(struct device *dev, struct rtc_time *tm) { return pcf85063_get_datetime(to_i2c_client(dev), tm); } static int pcf85063_rtc_set_time(struct device *dev, struct rtc_time *tm) { return pcf85063_set_datetime(to_i2c_client(dev), tm); } static const struct rtc_class_ops pcf85063_rtc_ops = { .read_time = pcf85063_rtc_read_time, .set_time = pcf85063_rtc_set_time }; static int pcf85063_probe(struct i2c_client *client, const struct i2c_device_id *id) { |
2da424af4
|
188 |
struct rtc_device *rtc; |
796b7abb3
|
189 190 191 192 193 194 |
dev_dbg(&client->dev, "%s ", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; |
2da424af4
|
195 196 197 |
rtc = devm_rtc_device_register(&client->dev, pcf85063_driver.driver.name, &pcf85063_rtc_ops, THIS_MODULE); |
796b7abb3
|
198 |
|
2da424af4
|
199 |
return PTR_ERR_OR_ZERO(rtc); |
796b7abb3
|
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
} static const struct i2c_device_id pcf85063_id[] = { { "pcf85063", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf85063_id); #ifdef CONFIG_OF static const struct of_device_id pcf85063_of_match[] = { { .compatible = "nxp,pcf85063" }, {} }; MODULE_DEVICE_TABLE(of, pcf85063_of_match); #endif static struct i2c_driver pcf85063_driver = { .driver = { .name = "rtc-pcf85063", |
796b7abb3
|
219 220 221 222 223 224 225 226 227 228 229 |
.of_match_table = of_match_ptr(pcf85063_of_match), }, .probe = pcf85063_probe, .id_table = pcf85063_id, }; module_i2c_driver(pcf85063_driver); MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>"); MODULE_DESCRIPTION("PCF85063 RTC driver"); MODULE_LICENSE("GPL"); |