aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDale Farnsworth <dale@farnsworth.org>2007-07-21 07:37:57 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-21 20:49:17 -0400
commit8a2601f6aa837903bfb385b138b50b1e305f3e04 (patch)
tree6e4815b7e8909f5bcd48e021caf1eb2b042cc4e0
parent55ff1aba940ff46d4f6d4fd790ea3e1a47aaa84f (diff)
rtc: update and use the MAX6900 century byte
We now read and write the century byte in the max6900 chip. We probably don't need to do so on Linux-only system, but it's necessary when the chip is shared by another OS that uses the century byte. Signed-off-by: Dale Farnsworth <dale@farnsworth.org> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rtc/rtc-max6900.c96
1 files changed, 72 insertions, 24 deletions
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index eee4ee5bb75a..a1cd448639c9 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -31,17 +31,24 @@
31#define MAX6900_REG_DW 5 /* day of week 1-7 */ 31#define MAX6900_REG_DW 5 /* day of week 1-7 */
32#define MAX6900_REG_YR 6 /* year 00-99 */ 32#define MAX6900_REG_YR 6 /* year 00-99 */
33#define MAX6900_REG_CT 7 /* control */ 33#define MAX6900_REG_CT 7 /* control */
34#define MAX6900_REG_LEN 8 34 /* register 8 is undocumented */
35#define MAX6900_REG_CENTURY 9 /* century */
36#define MAX6900_REG_LEN 10
37
38#define MAX6900_BURST_LEN 8 /* can burst r/w first 8 regs */
35 39
36#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */ 40#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */
37 41
42
38/* 43/*
39 * register read/write commands 44 * register read/write commands
40 */ 45 */
41#define MAX6900_REG_CONTROL_WRITE 0x8e 46#define MAX6900_REG_CONTROL_WRITE 0x8e
42#define MAX6900_REG_BURST_READ 0xbf 47#define MAX6900_REG_CENTURY_WRITE 0x92
43#define MAX6900_REG_BURST_WRITE 0xbe 48#define MAX6900_REG_CENTURY_READ 0x93
44#define MAX6900_REG_RESERVED_READ 0x96 49#define MAX6900_REG_RESERVED_READ 0x96
50#define MAX6900_REG_BURST_WRITE 0xbe
51#define MAX6900_REG_BURST_READ 0xbf
45 52
46#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */ 53#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */
47 54
@@ -58,19 +65,32 @@ static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
58 65
59static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) 66static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
60{ 67{
61 u8 reg_addr[1] = { MAX6900_REG_BURST_READ }; 68 u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ };
62 struct i2c_msg msgs[2] = { 69 u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
70 struct i2c_msg msgs[4] = {
63 { 71 {
64 .addr = client->addr, 72 .addr = client->addr,
65 .flags = 0, /* write */ 73 .flags = 0, /* write */
66 .len = sizeof(reg_addr), 74 .len = sizeof(reg_burst_read),
67 .buf = reg_addr 75 .buf = reg_burst_read
68 }, 76 },
69 { 77 {
70 .addr = client->addr, 78 .addr = client->addr,
71 .flags = I2C_M_RD, 79 .flags = I2C_M_RD,
72 .len = MAX6900_REG_LEN, 80 .len = MAX6900_BURST_LEN,
73 .buf = buf 81 .buf = buf
82 },
83 {
84 .addr = client->addr,
85 .flags = 0, /* write */
86 .len = sizeof(reg_century_read),
87 .buf = reg_century_read
88 },
89 {
90 .addr = client->addr,
91 .flags = I2C_M_RD,
92 .len = sizeof(buf[MAX6900_REG_CENTURY]),
93 .buf = &buf[MAX6900_REG_CENTURY]
74 } 94 }
75 }; 95 };
76 int rc; 96 int rc;
@@ -86,33 +106,58 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
86 106
87static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) 107static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
88{ 108{
89 u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE }; 109 u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
90 struct i2c_msg msgs[1] = { 110 struct i2c_msg century_msgs[1] = {
91 { 111 {
92 .addr = client->addr, 112 .addr = client->addr,
93 .flags = 0, /* write */ 113 .flags = 0, /* write */
94 .len = MAX6900_REG_LEN + 1, 114 .len = sizeof(i2c_century_buf),
95 .buf = i2c_buf 115 .buf = i2c_century_buf
116 }
117 };
118 u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
119 struct i2c_msg burst_msgs[1] = {
120 {
121 .addr = client->addr,
122 .flags = 0, /* write */
123 .len = sizeof(i2c_burst_buf),
124 .buf = i2c_burst_buf
96 } 125 }
97 }; 126 };
98 int rc; 127 int rc;
99 128
100 memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN); 129 /*
130 * We have to make separate calls to i2c_transfer because of
131 * the need to delay after each write to the chip. Also,
132 * we write the century byte first, since we set the write-protect
133 * bit as part of the burst write.
134 */
135 i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
136 rc = i2c_transfer(client->adapter, century_msgs,
137 ARRAY_SIZE(century_msgs));
138 if (rc != ARRAY_SIZE(century_msgs))
139 goto write_failed;
140 msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
101 141
102 rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 142 memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
103 if (rc != ARRAY_SIZE(msgs)) { 143
104 dev_err(&client->dev, "%s: register write failed\n", 144 rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs));
105 __FUNCTION__); 145 if (rc != ARRAY_SIZE(burst_msgs))
106 return -EIO; 146 goto write_failed;
107 }
108 msleep(MAX6900_IDLE_TIME_AFTER_WRITE); 147 msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
148
109 return 0; 149 return 0;
150
151write_failed:
152 dev_err(&client->dev, "%s: register write failed\n",
153 __FUNCTION__);
154 return -EIO;
110} 155}
111 156
112static int max6900_i2c_validate_client(struct i2c_client *client) 157static int max6900_i2c_validate_client(struct i2c_client *client)
113{ 158{
114 u8 regs[MAX6900_REG_LEN]; 159 u8 regs[MAX6900_REG_LEN];
115 u8 zero_mask[MAX6900_REG_LEN] = { 160 u8 zero_mask[] = {
116 0x80, /* seconds */ 161 0x80, /* seconds */
117 0x80, /* minutes */ 162 0x80, /* minutes */
118 0x40, /* hours */ 163 0x40, /* hours */
@@ -134,7 +179,7 @@ static int max6900_i2c_validate_client(struct i2c_client *client)
134 if (rc < 0) 179 if (rc < 0)
135 return rc; 180 return rc;
136 181
137 for (i = 0; i < MAX6900_REG_LEN; ++i) { 182 for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
138 if (regs[i] & zero_mask[i]) 183 if (regs[i] & zero_mask[i])
139 return -ENODEV; 184 return -ENODEV;
140 } 185 }
@@ -156,7 +201,8 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
156 tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f); 201 tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
157 tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]); 202 tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
158 tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1; 203 tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
159 tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100; 204 tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
205 BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
160 tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]); 206 tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
161 207
162 return 0; 208 return 0;
@@ -189,9 +235,11 @@ static int max6900_i2c_set_time(struct i2c_client *client,
189 regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour); 235 regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
190 regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday); 236 regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
191 regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1); 237 regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
192 regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
193 regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday); 238 regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
194 regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; /* set write protect */ 239 regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100);
240 regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100);
241 /* set write protect */
242 regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
195 243
196 rc = max6900_i2c_write_regs(client, regs); 244 rc = max6900_i2c_write_regs(client, regs);
197 if (rc < 0) 245 if (rc < 0)