diff options
Diffstat (limited to 'drivers/rtc/rtc-pcf8563.c')
| -rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 231 |
1 files changed, 201 insertions, 30 deletions
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 63b558c48196..c2ef0a22ee94 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | 26 | ||
| 27 | #define PCF8563_REG_ST1 0x00 /* status */ | 27 | #define PCF8563_REG_ST1 0x00 /* status */ |
| 28 | #define PCF8563_REG_ST2 0x01 | 28 | #define PCF8563_REG_ST2 0x01 |
| 29 | #define PCF8563_BIT_AIE (1 << 1) | ||
| 30 | #define PCF8563_BIT_AF (1 << 3) | ||
| 29 | 31 | ||
| 30 | #define PCF8563_REG_SC 0x02 /* datetime */ | 32 | #define PCF8563_REG_SC 0x02 /* datetime */ |
| 31 | #define PCF8563_REG_MN 0x03 | 33 | #define PCF8563_REG_MN 0x03 |
| @@ -36,9 +38,6 @@ | |||
| 36 | #define PCF8563_REG_YR 0x08 | 38 | #define PCF8563_REG_YR 0x08 |
| 37 | 39 | ||
| 38 | #define PCF8563_REG_AMN 0x09 /* alarm */ | 40 | #define PCF8563_REG_AMN 0x09 /* alarm */ |
| 39 | #define PCF8563_REG_AHR 0x0A | ||
| 40 | #define PCF8563_REG_ADM 0x0B | ||
| 41 | #define PCF8563_REG_ADW 0x0C | ||
| 42 | 41 | ||
| 43 | #define PCF8563_REG_CLKO 0x0D /* clock out */ | 42 | #define PCF8563_REG_CLKO 0x0D /* clock out */ |
| 44 | #define PCF8563_REG_TMRC 0x0E /* timer control */ | 43 | #define PCF8563_REG_TMRC 0x0E /* timer control */ |
| @@ -67,37 +66,133 @@ struct pcf8563 { | |||
| 67 | */ | 66 | */ |
| 68 | int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ | 67 | int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ |
| 69 | int voltage_low; /* incicates if a low_voltage was detected */ | 68 | int voltage_low; /* incicates if a low_voltage was detected */ |
| 69 | |||
| 70 | struct i2c_client *client; | ||
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 72 | /* | 73 | static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, |
| 73 | * In the routines that deal directly with the pcf8563 hardware, we use | 74 | unsigned char length, unsigned char *buf) |
| 74 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | ||
| 75 | */ | ||
| 76 | static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
| 77 | { | 75 | { |
| 78 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); | ||
| 79 | unsigned char buf[13] = { PCF8563_REG_ST1 }; | ||
| 80 | |||
| 81 | struct i2c_msg msgs[] = { | 76 | struct i2c_msg msgs[] = { |
| 82 | {/* setup read ptr */ | 77 | {/* setup read ptr */ |
| 83 | .addr = client->addr, | 78 | .addr = client->addr, |
| 84 | .len = 1, | 79 | .len = 1, |
| 85 | .buf = buf | 80 | .buf = ®, |
| 86 | }, | 81 | }, |
| 87 | {/* read status + date */ | 82 | { |
| 88 | .addr = client->addr, | 83 | .addr = client->addr, |
| 89 | .flags = I2C_M_RD, | 84 | .flags = I2C_M_RD, |
| 90 | .len = 13, | 85 | .len = length, |
| 91 | .buf = buf | 86 | .buf = buf |
| 92 | }, | 87 | }, |
| 93 | }; | 88 | }; |
| 94 | 89 | ||
| 95 | /* read registers */ | ||
| 96 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { | 90 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { |
| 97 | dev_err(&client->dev, "%s: read error\n", __func__); | 91 | dev_err(&client->dev, "%s: read error\n", __func__); |
| 98 | return -EIO; | 92 | return -EIO; |
| 99 | } | 93 | } |
| 100 | 94 | ||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int pcf8563_write_block_data(struct i2c_client *client, | ||
| 99 | unsigned char reg, unsigned char length, | ||
| 100 | unsigned char *buf) | ||
| 101 | { | ||
| 102 | int i, err; | ||
| 103 | |||
| 104 | for (i = 0; i < length; i++) { | ||
| 105 | unsigned char data[2] = { reg + i, buf[i] }; | ||
| 106 | |||
| 107 | err = i2c_master_send(client, data, sizeof(data)); | ||
| 108 | if (err != sizeof(data)) { | ||
| 109 | dev_err(&client->dev, | ||
| 110 | "%s: err=%d addr=%02x, data=%02x\n", | ||
| 111 | __func__, err, data[0], data[1]); | ||
| 112 | return -EIO; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) | ||
| 120 | { | ||
| 121 | unsigned char buf[2]; | ||
| 122 | int err; | ||
| 123 | |||
| 124 | err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1); | ||
| 125 | if (err < 0) | ||
| 126 | return err; | ||
| 127 | |||
| 128 | if (on) | ||
| 129 | buf[1] |= PCF8563_BIT_AIE; | ||
| 130 | else | ||
| 131 | buf[1] &= ~PCF8563_BIT_AIE; | ||
| 132 | |||
| 133 | buf[1] &= ~PCF8563_BIT_AF; | ||
| 134 | buf[0] = PCF8563_REG_ST2; | ||
| 135 | |||
| 136 | err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1); | ||
| 137 | if (err < 0) { | ||
| 138 | dev_err(&client->dev, "%s: write error\n", __func__); | ||
| 139 | return -EIO; | ||
| 140 | } | ||
| 141 | |||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en, | ||
| 146 | unsigned char *pen) | ||
| 147 | { | ||
| 148 | unsigned char buf; | ||
| 149 | int err; | ||
| 150 | |||
| 151 | err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); | ||
| 152 | if (err) | ||
| 153 | return err; | ||
| 154 | |||
| 155 | if (en) | ||
| 156 | *en = !!(buf & PCF8563_BIT_AIE); | ||
| 157 | if (pen) | ||
| 158 | *pen = !!(buf & PCF8563_BIT_AF); | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | static irqreturn_t pcf8563_irq(int irq, void *dev_id) | ||
| 164 | { | ||
| 165 | struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id); | ||
| 166 | int err; | ||
| 167 | char pending; | ||
| 168 | |||
| 169 | err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending); | ||
| 170 | if (err) | ||
| 171 | return IRQ_NONE; | ||
| 172 | |||
| 173 | if (pending) { | ||
| 174 | rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF); | ||
| 175 | pcf8563_set_alarm_mode(pcf8563->client, 1); | ||
| 176 | return IRQ_HANDLED; | ||
| 177 | } | ||
| 178 | |||
| 179 | return IRQ_NONE; | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 183 | * In the routines that deal directly with the pcf8563 hardware, we use | ||
| 184 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | ||
| 185 | */ | ||
| 186 | static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
| 187 | { | ||
| 188 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); | ||
| 189 | unsigned char buf[9]; | ||
| 190 | int err; | ||
| 191 | |||
| 192 | err = pcf8563_read_block_data(client, PCF8563_REG_ST1, 9, buf); | ||
| 193 | if (err) | ||
| 194 | return err; | ||
| 195 | |||
| 101 | if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) { | 196 | if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) { |
| 102 | pcf8563->voltage_low = 1; | 197 | pcf8563->voltage_low = 1; |
| 103 | dev_info(&client->dev, | 198 | dev_info(&client->dev, |
| @@ -144,7 +239,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
| 144 | static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) | 239 | static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) |
| 145 | { | 240 | { |
| 146 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); | 241 | struct pcf8563 *pcf8563 = i2c_get_clientdata(client); |
| 147 | int i, err; | 242 | int err; |
| 148 | unsigned char buf[9]; | 243 | unsigned char buf[9]; |
| 149 | 244 | ||
| 150 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " | 245 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " |
| @@ -170,19 +265,10 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) | |||
| 170 | 265 | ||
| 171 | buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; | 266 | buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; |
| 172 | 267 | ||
| 173 | /* write register's data */ | 268 | err = pcf8563_write_block_data(client, PCF8563_REG_SC, |
| 174 | for (i = 0; i < 7; i++) { | 269 | 9 - PCF8563_REG_SC, buf + PCF8563_REG_SC); |
| 175 | unsigned char data[2] = { PCF8563_REG_SC + i, | 270 | if (err) |
| 176 | buf[PCF8563_REG_SC + i] }; | 271 | return err; |
| 177 | |||
| 178 | err = i2c_master_send(client, data, sizeof(data)); | ||
| 179 | if (err != sizeof(data)) { | ||
| 180 | dev_err(&client->dev, | ||
| 181 | "%s: err=%d addr=%02x, data=%02x\n", | ||
| 182 | __func__, err, data[0], data[1]); | ||
| 183 | return -EIO; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | 272 | ||
| 187 | return 0; | 273 | return 0; |
| 188 | } | 274 | } |
| @@ -235,16 +321,83 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 235 | return pcf8563_set_datetime(to_i2c_client(dev), tm); | 321 | return pcf8563_set_datetime(to_i2c_client(dev), tm); |
| 236 | } | 322 | } |
| 237 | 323 | ||
| 324 | static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) | ||
| 325 | { | ||
| 326 | struct i2c_client *client = to_i2c_client(dev); | ||
| 327 | unsigned char buf[4]; | ||
| 328 | int err; | ||
| 329 | |||
| 330 | err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf); | ||
| 331 | if (err) | ||
| 332 | return err; | ||
| 333 | |||
| 334 | dev_dbg(&client->dev, | ||
| 335 | "%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n", | ||
| 336 | __func__, buf[0], buf[1], buf[2], buf[3]); | ||
| 337 | |||
| 338 | tm->time.tm_min = bcd2bin(buf[0] & 0x7F); | ||
| 339 | tm->time.tm_hour = bcd2bin(buf[1] & 0x7F); | ||
| 340 | tm->time.tm_mday = bcd2bin(buf[2] & 0x1F); | ||
| 341 | tm->time.tm_wday = bcd2bin(buf[3] & 0x7); | ||
| 342 | tm->time.tm_mon = -1; | ||
| 343 | tm->time.tm_year = -1; | ||
| 344 | tm->time.tm_yday = -1; | ||
| 345 | tm->time.tm_isdst = -1; | ||
| 346 | |||
| 347 | err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending); | ||
| 348 | if (err < 0) | ||
| 349 | return err; | ||
| 350 | |||
| 351 | dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d," | ||
| 352 | " enabled=%d, pending=%d\n", __func__, tm->time.tm_min, | ||
| 353 | tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday, | ||
| 354 | tm->enabled, tm->pending); | ||
| 355 | |||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) | ||
| 360 | { | ||
| 361 | struct i2c_client *client = to_i2c_client(dev); | ||
| 362 | unsigned char buf[4]; | ||
| 363 | int err; | ||
| 364 | |||
| 365 | dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d " | ||
| 366 | "enabled=%d pending=%d\n", __func__, | ||
| 367 | tm->time.tm_min, tm->time.tm_hour, tm->time.tm_wday, | ||
| 368 | tm->time.tm_mday, tm->enabled, tm->pending); | ||
| 369 | |||
| 370 | buf[0] = bin2bcd(tm->time.tm_min); | ||
| 371 | buf[1] = bin2bcd(tm->time.tm_hour); | ||
| 372 | buf[2] = bin2bcd(tm->time.tm_mday); | ||
| 373 | buf[3] = tm->time.tm_wday & 0x07; | ||
| 374 | |||
| 375 | err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf); | ||
| 376 | if (err) | ||
| 377 | return err; | ||
| 378 | |||
| 379 | return pcf8563_set_alarm_mode(client, 1); | ||
| 380 | } | ||
| 381 | |||
| 382 | static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) | ||
| 383 | { | ||
| 384 | return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); | ||
| 385 | } | ||
| 386 | |||
| 238 | static const struct rtc_class_ops pcf8563_rtc_ops = { | 387 | static const struct rtc_class_ops pcf8563_rtc_ops = { |
| 239 | .ioctl = pcf8563_rtc_ioctl, | 388 | .ioctl = pcf8563_rtc_ioctl, |
| 240 | .read_time = pcf8563_rtc_read_time, | 389 | .read_time = pcf8563_rtc_read_time, |
| 241 | .set_time = pcf8563_rtc_set_time, | 390 | .set_time = pcf8563_rtc_set_time, |
| 391 | .read_alarm = pcf8563_rtc_read_alarm, | ||
| 392 | .set_alarm = pcf8563_rtc_set_alarm, | ||
| 393 | .alarm_irq_enable = pcf8563_irq_enable, | ||
| 242 | }; | 394 | }; |
| 243 | 395 | ||
| 244 | static int pcf8563_probe(struct i2c_client *client, | 396 | static int pcf8563_probe(struct i2c_client *client, |
| 245 | const struct i2c_device_id *id) | 397 | const struct i2c_device_id *id) |
| 246 | { | 398 | { |
| 247 | struct pcf8563 *pcf8563; | 399 | struct pcf8563 *pcf8563; |
| 400 | int err; | ||
| 248 | 401 | ||
| 249 | dev_dbg(&client->dev, "%s\n", __func__); | 402 | dev_dbg(&client->dev, "%s\n", __func__); |
| 250 | 403 | ||
| @@ -259,12 +412,30 @@ static int pcf8563_probe(struct i2c_client *client, | |||
| 259 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | 412 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); |
| 260 | 413 | ||
| 261 | i2c_set_clientdata(client, pcf8563); | 414 | i2c_set_clientdata(client, pcf8563); |
| 415 | pcf8563->client = client; | ||
| 416 | device_set_wakeup_capable(&client->dev, 1); | ||
| 262 | 417 | ||
| 263 | pcf8563->rtc = devm_rtc_device_register(&client->dev, | 418 | pcf8563->rtc = devm_rtc_device_register(&client->dev, |
| 264 | pcf8563_driver.driver.name, | 419 | pcf8563_driver.driver.name, |
| 265 | &pcf8563_rtc_ops, THIS_MODULE); | 420 | &pcf8563_rtc_ops, THIS_MODULE); |
| 266 | 421 | ||
| 267 | return PTR_ERR_OR_ZERO(pcf8563->rtc); | 422 | if (IS_ERR(pcf8563->rtc)) |
| 423 | return PTR_ERR(pcf8563->rtc); | ||
| 424 | |||
| 425 | if (client->irq > 0) { | ||
| 426 | err = devm_request_threaded_irq(&client->dev, client->irq, | ||
| 427 | NULL, pcf8563_irq, | ||
| 428 | IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING, | ||
| 429 | pcf8563->rtc->name, client); | ||
| 430 | if (err) { | ||
| 431 | dev_err(&client->dev, "unable to request IRQ %d\n", | ||
| 432 | client->irq); | ||
| 433 | return err; | ||
| 434 | } | ||
| 435 | |||
| 436 | } | ||
| 437 | |||
| 438 | return 0; | ||
| 268 | } | 439 | } |
| 269 | 440 | ||
| 270 | static const struct i2c_device_id pcf8563_id[] = { | 441 | static const struct i2c_device_id pcf8563_id[] = { |
