diff options
Diffstat (limited to 'drivers/rtc/rtc-x1205.c')
| -rw-r--r-- | drivers/rtc/rtc-x1205.c | 111 |
1 files changed, 91 insertions, 20 deletions
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index eaf55945f21b..7dcfba1bbfe1 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c | |||
| @@ -71,6 +71,7 @@ | |||
| 71 | #define X1205_SR_RTCF 0x01 /* Clock failure */ | 71 | #define X1205_SR_RTCF 0x01 /* Clock failure */ |
| 72 | #define X1205_SR_WEL 0x02 /* Write Enable Latch */ | 72 | #define X1205_SR_WEL 0x02 /* Write Enable Latch */ |
| 73 | #define X1205_SR_RWEL 0x04 /* Register Write Enable */ | 73 | #define X1205_SR_RWEL 0x04 /* Register Write Enable */ |
| 74 | #define X1205_SR_AL0 0x20 /* Alarm 0 match */ | ||
| 74 | 75 | ||
| 75 | #define X1205_DTR_DTR0 0x01 | 76 | #define X1205_DTR_DTR0 0x01 |
| 76 | #define X1205_DTR_DTR1 0x02 | 77 | #define X1205_DTR_DTR1 0x02 |
| @@ -78,6 +79,8 @@ | |||
| 78 | 79 | ||
| 79 | #define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ | 80 | #define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ |
| 80 | 81 | ||
| 82 | #define X1205_INT_AL0E 0x20 /* Alarm 0 enable */ | ||
| 83 | |||
| 81 | static struct i2c_driver x1205_driver; | 84 | static struct i2c_driver x1205_driver; |
| 82 | 85 | ||
| 83 | /* | 86 | /* |
| @@ -89,8 +92,8 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
| 89 | unsigned char reg_base) | 92 | unsigned char reg_base) |
| 90 | { | 93 | { |
| 91 | unsigned char dt_addr[2] = { 0, reg_base }; | 94 | unsigned char dt_addr[2] = { 0, reg_base }; |
| 92 | |||
| 93 | unsigned char buf[8]; | 95 | unsigned char buf[8]; |
| 96 | int i; | ||
| 94 | 97 | ||
| 95 | struct i2c_msg msgs[] = { | 98 | struct i2c_msg msgs[] = { |
| 96 | { client->addr, 0, 2, dt_addr }, /* setup read ptr */ | 99 | { client->addr, 0, 2, dt_addr }, /* setup read ptr */ |
| @@ -98,7 +101,7 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
| 98 | }; | 101 | }; |
| 99 | 102 | ||
| 100 | /* read date registers */ | 103 | /* read date registers */ |
| 101 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | 104 | if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) { |
| 102 | dev_err(&client->dev, "%s: read error\n", __func__); | 105 | dev_err(&client->dev, "%s: read error\n", __func__); |
| 103 | return -EIO; | 106 | return -EIO; |
| 104 | } | 107 | } |
| @@ -110,6 +113,11 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
| 110 | buf[0], buf[1], buf[2], buf[3], | 113 | buf[0], buf[1], buf[2], buf[3], |
| 111 | buf[4], buf[5], buf[6], buf[7]); | 114 | buf[4], buf[5], buf[6], buf[7]); |
| 112 | 115 | ||
| 116 | /* Mask out the enable bits if these are alarm registers */ | ||
| 117 | if (reg_base < X1205_CCR_BASE) | ||
| 118 | for (i = 0; i <= 4; i++) | ||
| 119 | buf[i] &= 0x7F; | ||
| 120 | |||
| 113 | tm->tm_sec = BCD2BIN(buf[CCR_SEC]); | 121 | tm->tm_sec = BCD2BIN(buf[CCR_SEC]); |
| 114 | tm->tm_min = BCD2BIN(buf[CCR_MIN]); | 122 | tm->tm_min = BCD2BIN(buf[CCR_MIN]); |
| 115 | tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ | 123 | tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ |
| @@ -138,7 +146,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr) | |||
| 138 | }; | 146 | }; |
| 139 | 147 | ||
| 140 | /* read status register */ | 148 | /* read status register */ |
| 141 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | 149 | if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) { |
| 142 | dev_err(&client->dev, "%s: read error\n", __func__); | 150 | dev_err(&client->dev, "%s: read error\n", __func__); |
| 143 | return -EIO; | 151 | return -EIO; |
| 144 | } | 152 | } |
| @@ -147,10 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr) | |||
| 147 | } | 155 | } |
| 148 | 156 | ||
| 149 | static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | 157 | static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, |
| 150 | int datetoo, u8 reg_base) | 158 | int datetoo, u8 reg_base, unsigned char alm_enable) |
| 151 | { | 159 | { |
| 152 | int i, xfer; | 160 | int i, xfer, nbytes; |
| 153 | unsigned char buf[8]; | 161 | unsigned char buf[8]; |
| 162 | unsigned char rdata[10] = { 0, reg_base }; | ||
| 154 | 163 | ||
| 155 | static const unsigned char wel[3] = { 0, X1205_REG_SR, | 164 | static const unsigned char wel[3] = { 0, X1205_REG_SR, |
| 156 | X1205_SR_WEL }; | 165 | X1205_SR_WEL }; |
| @@ -189,6 +198,11 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
| 189 | buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100); | 198 | buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100); |
| 190 | } | 199 | } |
| 191 | 200 | ||
| 201 | /* If writing alarm registers, set compare bits on registers 0-4 */ | ||
| 202 | if (reg_base < X1205_CCR_BASE) | ||
| 203 | for (i = 0; i <= 4; i++) | ||
| 204 | buf[i] |= 0x80; | ||
| 205 | |||
| 192 | /* this sequence is required to unlock the chip */ | 206 | /* this sequence is required to unlock the chip */ |
| 193 | if ((xfer = i2c_master_send(client, wel, 3)) != 3) { | 207 | if ((xfer = i2c_master_send(client, wel, 3)) != 3) { |
| 194 | dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); | 208 | dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); |
| @@ -200,19 +214,57 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
| 200 | return -EIO; | 214 | return -EIO; |
| 201 | } | 215 | } |
| 202 | 216 | ||
| 217 | |||
| 203 | /* write register's data */ | 218 | /* write register's data */ |
| 204 | for (i = 0; i < (datetoo ? 8 : 3); i++) { | 219 | if (datetoo) |
| 205 | unsigned char rdata[3] = { 0, reg_base + i, buf[i] }; | 220 | nbytes = 8; |
| 221 | else | ||
| 222 | nbytes = 3; | ||
| 223 | for (i = 0; i < nbytes; i++) | ||
| 224 | rdata[2+i] = buf[i]; | ||
| 225 | |||
| 226 | xfer = i2c_master_send(client, rdata, nbytes+2); | ||
| 227 | if (xfer != nbytes+2) { | ||
| 228 | dev_err(&client->dev, | ||
| 229 | "%s: result=%d addr=%02x, data=%02x\n", | ||
| 230 | __func__, | ||
| 231 | xfer, rdata[1], rdata[2]); | ||
| 232 | return -EIO; | ||
| 233 | } | ||
| 234 | |||
| 235 | /* If we wrote to the nonvolatile region, wait 10msec for write cycle*/ | ||
| 236 | if (reg_base < X1205_CCR_BASE) { | ||
| 237 | unsigned char al0e[3] = { 0, X1205_REG_INT, 0 }; | ||
| 238 | |||
| 239 | msleep(10); | ||
| 206 | 240 | ||
| 207 | xfer = i2c_master_send(client, rdata, 3); | 241 | /* ...and set or clear the AL0E bit in the INT register */ |
| 242 | |||
| 243 | /* Need to set RWEL again as the write has cleared it */ | ||
| 244 | xfer = i2c_master_send(client, rwel, 3); | ||
| 208 | if (xfer != 3) { | 245 | if (xfer != 3) { |
| 209 | dev_err(&client->dev, | 246 | dev_err(&client->dev, |
| 210 | "%s: xfer=%d addr=%02x, data=%02x\n", | 247 | "%s: aloe rwel - %d\n", |
| 211 | __func__, | 248 | __func__, |
| 212 | xfer, rdata[1], rdata[2]); | 249 | xfer); |
| 250 | return -EIO; | ||
| 251 | } | ||
| 252 | |||
| 253 | if (alm_enable) | ||
| 254 | al0e[2] = X1205_INT_AL0E; | ||
| 255 | |||
| 256 | xfer = i2c_master_send(client, al0e, 3); | ||
| 257 | if (xfer != 3) { | ||
| 258 | dev_err(&client->dev, | ||
| 259 | "%s: al0e - %d\n", | ||
| 260 | __func__, | ||
| 261 | xfer); | ||
| 213 | return -EIO; | 262 | return -EIO; |
| 214 | } | 263 | } |
| 215 | }; | 264 | |
| 265 | /* and wait 10msec again for this write to complete */ | ||
| 266 | msleep(10); | ||
| 267 | } | ||
| 216 | 268 | ||
| 217 | /* disable further writes */ | 269 | /* disable further writes */ |
| 218 | if ((xfer = i2c_master_send(client, diswe, 3)) != 3) { | 270 | if ((xfer = i2c_master_send(client, diswe, 3)) != 3) { |
| @@ -230,9 +282,9 @@ static int x1205_fix_osc(struct i2c_client *client) | |||
| 230 | 282 | ||
| 231 | tm.tm_hour = tm.tm_min = tm.tm_sec = 0; | 283 | tm.tm_hour = tm.tm_min = tm.tm_sec = 0; |
| 232 | 284 | ||
| 233 | if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0) | 285 | err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0); |
| 234 | dev_err(&client->dev, | 286 | if (err < 0) |
| 235 | "unable to restart the oscillator\n"); | 287 | dev_err(&client->dev, "unable to restart the oscillator\n"); |
| 236 | 288 | ||
| 237 | return err; | 289 | return err; |
| 238 | } | 290 | } |
| @@ -248,7 +300,7 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim) | |||
| 248 | }; | 300 | }; |
| 249 | 301 | ||
| 250 | /* read dtr register */ | 302 | /* read dtr register */ |
| 251 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | 303 | if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) { |
| 252 | dev_err(&client->dev, "%s: read error\n", __func__); | 304 | dev_err(&client->dev, "%s: read error\n", __func__); |
| 253 | return -EIO; | 305 | return -EIO; |
| 254 | } | 306 | } |
| @@ -280,7 +332,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) | |||
| 280 | }; | 332 | }; |
| 281 | 333 | ||
| 282 | /* read atr register */ | 334 | /* read atr register */ |
| 283 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | 335 | if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) { |
| 284 | dev_err(&client->dev, "%s: read error\n", __func__); | 336 | dev_err(&client->dev, "%s: read error\n", __func__); |
| 285 | return -EIO; | 337 | return -EIO; |
| 286 | } | 338 | } |
| @@ -403,14 +455,33 @@ static int x1205_validate_client(struct i2c_client *client) | |||
| 403 | 455 | ||
| 404 | static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 456 | static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
| 405 | { | 457 | { |
| 406 | return x1205_get_datetime(to_i2c_client(dev), | 458 | int err; |
| 407 | &alrm->time, X1205_ALM0_BASE); | 459 | unsigned char intreg, status; |
| 460 | static unsigned char int_addr[2] = { 0, X1205_REG_INT }; | ||
| 461 | struct i2c_client *client = to_i2c_client(dev); | ||
| 462 | struct i2c_msg msgs[] = { | ||
| 463 | { client->addr, 0, 2, int_addr }, /* setup read ptr */ | ||
| 464 | { client->addr, I2C_M_RD, 1, &intreg }, /* read INT register */ | ||
| 465 | }; | ||
| 466 | |||
| 467 | /* read interrupt register and status register */ | ||
| 468 | if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) { | ||
| 469 | dev_err(&client->dev, "%s: read error\n", __func__); | ||
| 470 | return -EIO; | ||
| 471 | } | ||
| 472 | err = x1205_get_status(client, &status); | ||
| 473 | if (err == 0) { | ||
| 474 | alrm->pending = (status & X1205_SR_AL0) ? 1 : 0; | ||
| 475 | alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0; | ||
| 476 | err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE); | ||
| 477 | } | ||
| 478 | return err; | ||
| 408 | } | 479 | } |
| 409 | 480 | ||
| 410 | static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 481 | static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
| 411 | { | 482 | { |
| 412 | return x1205_set_datetime(to_i2c_client(dev), | 483 | return x1205_set_datetime(to_i2c_client(dev), |
| 413 | &alrm->time, 1, X1205_ALM0_BASE); | 484 | &alrm->time, 1, X1205_ALM0_BASE, alrm->enabled); |
| 414 | } | 485 | } |
| 415 | 486 | ||
| 416 | static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) | 487 | static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) |
| @@ -422,7 +493,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
| 422 | static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm) | 493 | static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm) |
| 423 | { | 494 | { |
| 424 | return x1205_set_datetime(to_i2c_client(dev), | 495 | return x1205_set_datetime(to_i2c_client(dev), |
| 425 | tm, 1, X1205_CCR_BASE); | 496 | tm, 1, X1205_CCR_BASE, 0); |
| 426 | } | 497 | } |
| 427 | 498 | ||
| 428 | static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) | 499 | static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) |
