diff options
Diffstat (limited to 'drivers/rtc/rtc-isl1208.c')
| -rw-r--r-- | drivers/rtc/rtc-isl1208.c | 357 |
1 files changed, 170 insertions, 187 deletions
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 725b0c73c333..fb15e3fb4ce2 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c | |||
| @@ -15,16 +15,15 @@ | |||
| 15 | #include <linux/bcd.h> | 15 | #include <linux/bcd.h> |
| 16 | #include <linux/rtc.h> | 16 | #include <linux/rtc.h> |
| 17 | 17 | ||
| 18 | #define DRV_NAME "isl1208" | 18 | #define DRV_VERSION "0.3" |
| 19 | #define DRV_VERSION "0.2" | ||
| 20 | 19 | ||
| 21 | /* Register map */ | 20 | /* Register map */ |
| 22 | /* rtc section */ | 21 | /* rtc section */ |
| 23 | #define ISL1208_REG_SC 0x00 | 22 | #define ISL1208_REG_SC 0x00 |
| 24 | #define ISL1208_REG_MN 0x01 | 23 | #define ISL1208_REG_MN 0x01 |
| 25 | #define ISL1208_REG_HR 0x02 | 24 | #define ISL1208_REG_HR 0x02 |
| 26 | #define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ | 25 | #define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */ |
| 27 | #define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ | 26 | #define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ |
| 28 | #define ISL1208_REG_DT 0x03 | 27 | #define ISL1208_REG_DT 0x03 |
| 29 | #define ISL1208_REG_MO 0x04 | 28 | #define ISL1208_REG_MO 0x04 |
| 30 | #define ISL1208_REG_YR 0x05 | 29 | #define ISL1208_REG_YR 0x05 |
| @@ -33,14 +32,14 @@ | |||
| 33 | 32 | ||
| 34 | /* control/status section */ | 33 | /* control/status section */ |
| 35 | #define ISL1208_REG_SR 0x07 | 34 | #define ISL1208_REG_SR 0x07 |
| 36 | #define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ | 35 | #define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ |
| 37 | #define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ | 36 | #define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ |
| 38 | #define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ | 37 | #define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ |
| 39 | #define ISL1208_REG_SR_ALM (1<<2) /* alarm */ | 38 | #define ISL1208_REG_SR_ALM (1<<2) /* alarm */ |
| 40 | #define ISL1208_REG_SR_BAT (1<<1) /* battery */ | 39 | #define ISL1208_REG_SR_BAT (1<<1) /* battery */ |
| 41 | #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ | 40 | #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ |
| 42 | #define ISL1208_REG_INT 0x08 | 41 | #define ISL1208_REG_INT 0x08 |
| 43 | #define ISL1208_REG_09 0x09 /* reserved */ | 42 | #define ISL1208_REG_09 0x09 /* reserved */ |
| 44 | #define ISL1208_REG_ATR 0x0a | 43 | #define ISL1208_REG_ATR 0x0a |
| 45 | #define ISL1208_REG_DTR 0x0b | 44 | #define ISL1208_REG_DTR 0x0b |
| 46 | 45 | ||
| @@ -58,39 +57,21 @@ | |||
| 58 | #define ISL1208_REG_USR2 0x13 | 57 | #define ISL1208_REG_USR2 0x13 |
| 59 | #define ISL1208_USR_SECTION_LEN 2 | 58 | #define ISL1208_USR_SECTION_LEN 2 |
| 60 | 59 | ||
| 61 | /* i2c configuration */ | 60 | static struct i2c_driver isl1208_driver; |
| 62 | #define ISL1208_I2C_ADDR 0xde | ||
| 63 | |||
| 64 | static const unsigned short normal_i2c[] = { | ||
| 65 | ISL1208_I2C_ADDR>>1, I2C_CLIENT_END | ||
| 66 | }; | ||
| 67 | I2C_CLIENT_INSMOD; /* defines addr_data */ | ||
| 68 | |||
| 69 | static int isl1208_attach_adapter(struct i2c_adapter *adapter); | ||
| 70 | static int isl1208_detach_client(struct i2c_client *client); | ||
| 71 | |||
| 72 | static struct i2c_driver isl1208_driver = { | ||
| 73 | .driver = { | ||
| 74 | .name = DRV_NAME, | ||
| 75 | }, | ||
| 76 | .id = I2C_DRIVERID_ISL1208, | ||
| 77 | .attach_adapter = &isl1208_attach_adapter, | ||
| 78 | .detach_client = &isl1208_detach_client, | ||
| 79 | }; | ||
| 80 | 61 | ||
| 81 | /* block read */ | 62 | /* block read */ |
| 82 | static int | 63 | static int |
| 83 | isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], | 64 | isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], |
| 84 | unsigned len) | 65 | unsigned len) |
| 85 | { | 66 | { |
| 86 | u8 reg_addr[1] = { reg }; | 67 | u8 reg_addr[1] = { reg }; |
| 87 | struct i2c_msg msgs[2] = { | 68 | struct i2c_msg msgs[2] = { |
| 88 | { client->addr, client->flags, sizeof(reg_addr), reg_addr }, | 69 | {client->addr, 0, sizeof(reg_addr), reg_addr} |
| 89 | { client->addr, client->flags | I2C_M_RD, len, buf } | 70 | , |
| 71 | {client->addr, I2C_M_RD, len, buf} | ||
| 90 | }; | 72 | }; |
| 91 | int ret; | 73 | int ret; |
| 92 | 74 | ||
| 93 | BUG_ON(len == 0); | ||
| 94 | BUG_ON(reg > ISL1208_REG_USR2); | 75 | BUG_ON(reg > ISL1208_REG_USR2); |
| 95 | BUG_ON(reg + len > ISL1208_REG_USR2 + 1); | 76 | BUG_ON(reg + len > ISL1208_REG_USR2 + 1); |
| 96 | 77 | ||
| @@ -103,15 +84,14 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], | |||
| 103 | /* block write */ | 84 | /* block write */ |
| 104 | static int | 85 | static int |
| 105 | isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], | 86 | isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], |
| 106 | unsigned len) | 87 | unsigned len) |
| 107 | { | 88 | { |
| 108 | u8 i2c_buf[ISL1208_REG_USR2 + 2]; | 89 | u8 i2c_buf[ISL1208_REG_USR2 + 2]; |
| 109 | struct i2c_msg msgs[1] = { | 90 | struct i2c_msg msgs[1] = { |
| 110 | { client->addr, client->flags, len + 1, i2c_buf } | 91 | {client->addr, 0, len + 1, i2c_buf} |
| 111 | }; | 92 | }; |
| 112 | int ret; | 93 | int ret; |
| 113 | 94 | ||
| 114 | BUG_ON(len == 0); | ||
| 115 | BUG_ON(reg > ISL1208_REG_USR2); | 95 | BUG_ON(reg > ISL1208_REG_USR2); |
| 116 | BUG_ON(reg + len > ISL1208_REG_USR2 + 1); | 96 | BUG_ON(reg + len > ISL1208_REG_USR2 + 1); |
| 117 | 97 | ||
| @@ -125,7 +105,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], | |||
| 125 | } | 105 | } |
| 126 | 106 | ||
| 127 | /* simple check to see wether we have a isl1208 */ | 107 | /* simple check to see wether we have a isl1208 */ |
| 128 | static int isl1208_i2c_validate_client(struct i2c_client *client) | 108 | static int |
| 109 | isl1208_i2c_validate_client(struct i2c_client *client) | ||
| 129 | { | 110 | { |
| 130 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; | 111 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; |
| 131 | u8 zero_mask[ISL1208_RTC_SECTION_LEN] = { | 112 | u8 zero_mask[ISL1208_RTC_SECTION_LEN] = { |
| @@ -139,24 +120,29 @@ static int isl1208_i2c_validate_client(struct i2c_client *client) | |||
| 139 | return ret; | 120 | return ret; |
| 140 | 121 | ||
| 141 | for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) { | 122 | for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) { |
| 142 | if (regs[i] & zero_mask[i]) /* check if bits are cleared */ | 123 | if (regs[i] & zero_mask[i]) /* check if bits are cleared */ |
| 143 | return -ENODEV; | 124 | return -ENODEV; |
| 144 | } | 125 | } |
| 145 | 126 | ||
| 146 | return 0; | 127 | return 0; |
| 147 | } | 128 | } |
| 148 | 129 | ||
| 149 | static int isl1208_i2c_get_sr(struct i2c_client *client) | 130 | static int |
| 131 | isl1208_i2c_get_sr(struct i2c_client *client) | ||
| 150 | { | 132 | { |
| 151 | return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0; | 133 | int sr = i2c_smbus_read_byte_data(client, ISL1208_REG_SR); |
| 134 | if (sr < 0) | ||
| 135 | return -EIO; | ||
| 136 | |||
| 137 | return sr; | ||
| 152 | } | 138 | } |
| 153 | 139 | ||
| 154 | static int isl1208_i2c_get_atr(struct i2c_client *client) | 140 | static int |
| 141 | isl1208_i2c_get_atr(struct i2c_client *client) | ||
| 155 | { | 142 | { |
| 156 | int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR); | 143 | int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR); |
| 157 | |||
| 158 | if (atr < 0) | 144 | if (atr < 0) |
| 159 | return -EIO; | 145 | return atr; |
| 160 | 146 | ||
| 161 | /* The 6bit value in the ATR register controls the load | 147 | /* The 6bit value in the ATR register controls the load |
| 162 | * capacitance C_load * in steps of 0.25pF | 148 | * capacitance C_load * in steps of 0.25pF |
| @@ -169,51 +155,54 @@ static int isl1208_i2c_get_atr(struct i2c_client *client) | |||
| 169 | * | 155 | * |
| 170 | */ | 156 | */ |
| 171 | 157 | ||
| 172 | atr &= 0x3f; /* mask out lsb */ | 158 | atr &= 0x3f; /* mask out lsb */ |
| 173 | atr ^= 1<<5; /* invert 6th bit */ | 159 | atr ^= 1 << 5; /* invert 6th bit */ |
| 174 | atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ | 160 | atr += 2 * 9; /* add offset of 4.5pF; unit[atr] = 0.25pF */ |
| 175 | 161 | ||
| 176 | return atr; | 162 | return atr; |
| 177 | } | 163 | } |
| 178 | 164 | ||
| 179 | static int isl1208_i2c_get_dtr(struct i2c_client *client) | 165 | static int |
| 166 | isl1208_i2c_get_dtr(struct i2c_client *client) | ||
| 180 | { | 167 | { |
| 181 | int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR); | 168 | int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR); |
| 182 | |||
| 183 | if (dtr < 0) | 169 | if (dtr < 0) |
| 184 | return -EIO; | 170 | return -EIO; |
| 185 | 171 | ||
| 186 | /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ | 172 | /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ |
| 187 | dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1); | 173 | dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1); |
| 188 | 174 | ||
| 189 | return dtr; | 175 | return dtr; |
| 190 | } | 176 | } |
| 191 | 177 | ||
| 192 | static int isl1208_i2c_get_usr(struct i2c_client *client) | 178 | static int |
| 179 | isl1208_i2c_get_usr(struct i2c_client *client) | ||
| 193 | { | 180 | { |
| 194 | u8 buf[ISL1208_USR_SECTION_LEN] = { 0, }; | 181 | u8 buf[ISL1208_USR_SECTION_LEN] = { 0, }; |
| 195 | int ret; | 182 | int ret; |
| 196 | 183 | ||
| 197 | ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf, | 184 | ret = isl1208_i2c_read_regs(client, ISL1208_REG_USR1, buf, |
| 198 | ISL1208_USR_SECTION_LEN); | 185 | ISL1208_USR_SECTION_LEN); |
| 199 | if (ret < 0) | 186 | if (ret < 0) |
| 200 | return ret; | 187 | return ret; |
| 201 | 188 | ||
| 202 | return (buf[1] << 8) | buf[0]; | 189 | return (buf[1] << 8) | buf[0]; |
| 203 | } | 190 | } |
| 204 | 191 | ||
| 205 | static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) | 192 | static int |
| 193 | isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) | ||
| 206 | { | 194 | { |
| 207 | u8 buf[ISL1208_USR_SECTION_LEN]; | 195 | u8 buf[ISL1208_USR_SECTION_LEN]; |
| 208 | 196 | ||
| 209 | buf[0] = usr & 0xff; | 197 | buf[0] = usr & 0xff; |
| 210 | buf[1] = (usr >> 8) & 0xff; | 198 | buf[1] = (usr >> 8) & 0xff; |
| 211 | 199 | ||
| 212 | return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf, | 200 | return isl1208_i2c_set_regs(client, ISL1208_REG_USR1, buf, |
| 213 | ISL1208_USR_SECTION_LEN); | 201 | ISL1208_USR_SECTION_LEN); |
| 214 | } | 202 | } |
| 215 | 203 | ||
| 216 | static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) | 204 | static int |
| 205 | isl1208_rtc_proc(struct device *dev, struct seq_file *seq) | ||
| 217 | { | 206 | { |
| 218 | struct i2c_client *const client = to_i2c_client(dev); | 207 | struct i2c_client *const client = to_i2c_client(dev); |
| 219 | int sr, dtr, atr, usr; | 208 | int sr, dtr, atr, usr; |
| @@ -230,20 +219,19 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) | |||
| 230 | (sr & ISL1208_REG_SR_ALM) ? " ALM" : "", | 219 | (sr & ISL1208_REG_SR_ALM) ? " ALM" : "", |
| 231 | (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "", | 220 | (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "", |
| 232 | (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "", | 221 | (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "", |
| 233 | (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", | 222 | (sr & ISL1208_REG_SR_ARST) ? " ARST" : "", sr); |
| 234 | sr); | ||
| 235 | 223 | ||
| 236 | seq_printf(seq, "batt_status\t: %s\n", | 224 | seq_printf(seq, "batt_status\t: %s\n", |
| 237 | (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); | 225 | (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); |
| 238 | 226 | ||
| 239 | dtr = isl1208_i2c_get_dtr(client); | 227 | dtr = isl1208_i2c_get_dtr(client); |
| 240 | if (dtr >= 0 -1) | 228 | if (dtr >= 0 - 1) |
| 241 | seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); | 229 | seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); |
| 242 | 230 | ||
| 243 | atr = isl1208_i2c_get_atr(client); | 231 | atr = isl1208_i2c_get_atr(client); |
| 244 | if (atr >= 0) | 232 | if (atr >= 0) |
| 245 | seq_printf(seq, "analog_trim\t: %d.%.2d pF\n", | 233 | seq_printf(seq, "analog_trim\t: %d.%.2d pF\n", |
| 246 | atr>>2, (atr&0x3)*25); | 234 | atr >> 2, (atr & 0x3) * 25); |
| 247 | 235 | ||
| 248 | usr = isl1208_i2c_get_usr(client); | 236 | usr = isl1208_i2c_get_usr(client); |
| 249 | if (usr >= 0) | 237 | if (usr >= 0) |
| @@ -252,9 +240,8 @@ static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) | |||
| 252 | return 0; | 240 | return 0; |
| 253 | } | 241 | } |
| 254 | 242 | ||
| 255 | 243 | static int | |
| 256 | static int isl1208_i2c_read_time(struct i2c_client *client, | 244 | isl1208_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) |
| 257 | struct rtc_time *tm) | ||
| 258 | { | 245 | { |
| 259 | int sr; | 246 | int sr; |
| 260 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; | 247 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; |
| @@ -274,27 +261,30 @@ static int isl1208_i2c_read_time(struct i2c_client *client, | |||
| 274 | 261 | ||
| 275 | tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]); | 262 | tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]); |
| 276 | tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]); | 263 | tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]); |
| 277 | { /* HR field has a more complex interpretation */ | 264 | |
| 265 | /* HR field has a more complex interpretation */ | ||
| 266 | { | ||
| 278 | const u8 _hr = regs[ISL1208_REG_HR]; | 267 | const u8 _hr = regs[ISL1208_REG_HR]; |
| 279 | if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ | 268 | if (_hr & ISL1208_REG_HR_MIL) /* 24h format */ |
| 280 | tm->tm_hour = BCD2BIN(_hr & 0x3f); | 269 | tm->tm_hour = BCD2BIN(_hr & 0x3f); |
| 281 | else { // 12h format | 270 | else { |
| 271 | /* 12h format */ | ||
| 282 | tm->tm_hour = BCD2BIN(_hr & 0x1f); | 272 | tm->tm_hour = BCD2BIN(_hr & 0x1f); |
| 283 | if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ | 273 | if (_hr & ISL1208_REG_HR_PM) /* PM flag set */ |
| 284 | tm->tm_hour += 12; | 274 | tm->tm_hour += 12; |
| 285 | } | 275 | } |
| 286 | } | 276 | } |
| 287 | 277 | ||
| 288 | tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]); | 278 | tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]); |
| 289 | tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ | 279 | tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */ |
| 290 | tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100; | 280 | tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100; |
| 291 | tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]); | 281 | tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]); |
| 292 | 282 | ||
| 293 | return 0; | 283 | return 0; |
| 294 | } | 284 | } |
| 295 | 285 | ||
| 296 | static int isl1208_i2c_read_alarm(struct i2c_client *client, | 286 | static int |
| 297 | struct rtc_wkalrm *alarm) | 287 | isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) |
| 298 | { | 288 | { |
| 299 | struct rtc_time *const tm = &alarm->time; | 289 | struct rtc_time *const tm = &alarm->time; |
| 300 | u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; | 290 | u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; |
| @@ -307,7 +297,7 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client, | |||
| 307 | } | 297 | } |
| 308 | 298 | ||
| 309 | sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs, | 299 | sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs, |
| 310 | ISL1208_ALARM_SECTION_LEN); | 300 | ISL1208_ALARM_SECTION_LEN); |
| 311 | if (sr < 0) { | 301 | if (sr < 0) { |
| 312 | dev_err(&client->dev, "%s: reading alarm section failed\n", | 302 | dev_err(&client->dev, "%s: reading alarm section failed\n", |
| 313 | __func__); | 303 | __func__); |
| @@ -315,23 +305,25 @@ static int isl1208_i2c_read_alarm(struct i2c_client *client, | |||
| 315 | } | 305 | } |
| 316 | 306 | ||
| 317 | /* MSB of each alarm register is an enable bit */ | 307 | /* MSB of each alarm register is an enable bit */ |
| 318 | tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f); | 308 | tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA - ISL1208_REG_SCA] & 0x7f); |
| 319 | tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f); | 309 | tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA - ISL1208_REG_SCA] & 0x7f); |
| 320 | tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f); | 310 | tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA - ISL1208_REG_SCA] & 0x3f); |
| 321 | tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f); | 311 | tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA - ISL1208_REG_SCA] & 0x3f); |
| 322 | tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1; | 312 | tm->tm_mon = |
| 323 | tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03); | 313 | BCD2BIN(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1; |
| 314 | tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03); | ||
| 324 | 315 | ||
| 325 | return 0; | 316 | return 0; |
| 326 | } | 317 | } |
| 327 | 318 | ||
| 328 | static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) | 319 | static int |
| 320 | isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 329 | { | 321 | { |
| 330 | return isl1208_i2c_read_time(to_i2c_client(dev), tm); | 322 | return isl1208_i2c_read_time(to_i2c_client(dev), tm); |
| 331 | } | 323 | } |
| 332 | 324 | ||
| 333 | static int isl1208_i2c_set_time(struct i2c_client *client, | 325 | static int |
| 334 | struct rtc_time const *tm) | 326 | isl1208_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) |
| 335 | { | 327 | { |
| 336 | int sr; | 328 | int sr; |
| 337 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; | 329 | u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, }; |
| @@ -353,7 +345,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client, | |||
| 353 | } | 345 | } |
| 354 | 346 | ||
| 355 | /* set WRTC */ | 347 | /* set WRTC */ |
| 356 | sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, | 348 | sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, |
| 357 | sr | ISL1208_REG_SR_WRTC); | 349 | sr | ISL1208_REG_SR_WRTC); |
| 358 | if (sr < 0) { | 350 | if (sr < 0) { |
| 359 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); | 351 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); |
| @@ -369,7 +361,7 @@ static int isl1208_i2c_set_time(struct i2c_client *client, | |||
| 369 | } | 361 | } |
| 370 | 362 | ||
| 371 | /* clear WRTC again */ | 363 | /* clear WRTC again */ |
| 372 | sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR, | 364 | sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, |
| 373 | sr & ~ISL1208_REG_SR_WRTC); | 365 | sr & ~ISL1208_REG_SR_WRTC); |
| 374 | if (sr < 0) { | 366 | if (sr < 0) { |
| 375 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); | 367 | dev_err(&client->dev, "%s: writing SR failed\n", __func__); |
| @@ -380,70 +372,69 @@ static int isl1208_i2c_set_time(struct i2c_client *client, | |||
| 380 | } | 372 | } |
| 381 | 373 | ||
| 382 | 374 | ||
| 383 | static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) | 375 | static int |
| 376 | isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 384 | { | 377 | { |
| 385 | return isl1208_i2c_set_time(to_i2c_client(dev), tm); | 378 | return isl1208_i2c_set_time(to_i2c_client(dev), tm); |
| 386 | } | 379 | } |
| 387 | 380 | ||
| 388 | static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | 381 | static int |
| 382 | isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
| 389 | { | 383 | { |
| 390 | return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); | 384 | return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); |
| 391 | } | 385 | } |
| 392 | 386 | ||
| 393 | static const struct rtc_class_ops isl1208_rtc_ops = { | 387 | static const struct rtc_class_ops isl1208_rtc_ops = { |
| 394 | .proc = isl1208_rtc_proc, | 388 | .proc = isl1208_rtc_proc, |
| 395 | .read_time = isl1208_rtc_read_time, | 389 | .read_time = isl1208_rtc_read_time, |
| 396 | .set_time = isl1208_rtc_set_time, | 390 | .set_time = isl1208_rtc_set_time, |
| 397 | .read_alarm = isl1208_rtc_read_alarm, | 391 | .read_alarm = isl1208_rtc_read_alarm, |
| 398 | //.set_alarm = isl1208_rtc_set_alarm, | 392 | /*.set_alarm = isl1208_rtc_set_alarm, */ |
| 399 | }; | 393 | }; |
| 400 | 394 | ||
| 401 | /* sysfs interface */ | 395 | /* sysfs interface */ |
| 402 | 396 | ||
| 403 | static ssize_t isl1208_sysfs_show_atrim(struct device *dev, | 397 | static ssize_t |
| 404 | struct device_attribute *attr, | 398 | isl1208_sysfs_show_atrim(struct device *dev, |
| 405 | char *buf) | 399 | struct device_attribute *attr, char *buf) |
| 406 | { | 400 | { |
| 407 | int atr; | 401 | int atr = isl1208_i2c_get_atr(to_i2c_client(dev)); |
| 408 | |||
| 409 | atr = isl1208_i2c_get_atr(to_i2c_client(dev)); | ||
| 410 | if (atr < 0) | 402 | if (atr < 0) |
| 411 | return atr; | 403 | return atr; |
| 412 | 404 | ||
| 413 | return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25); | 405 | return sprintf(buf, "%d.%.2d pF\n", atr >> 2, (atr & 0x3) * 25); |
| 414 | } | 406 | } |
| 407 | |||
| 415 | static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL); | 408 | static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL); |
| 416 | 409 | ||
| 417 | static ssize_t isl1208_sysfs_show_dtrim(struct device *dev, | 410 | static ssize_t |
| 418 | struct device_attribute *attr, | 411 | isl1208_sysfs_show_dtrim(struct device *dev, |
| 419 | char *buf) | 412 | struct device_attribute *attr, char *buf) |
| 420 | { | 413 | { |
| 421 | int dtr; | 414 | int dtr = isl1208_i2c_get_dtr(to_i2c_client(dev)); |
| 422 | |||
| 423 | dtr = isl1208_i2c_get_dtr(to_i2c_client(dev)); | ||
| 424 | if (dtr < 0) | 415 | if (dtr < 0) |
| 425 | return dtr; | 416 | return dtr; |
| 426 | 417 | ||
| 427 | return sprintf(buf, "%d ppm\n", dtr); | 418 | return sprintf(buf, "%d ppm\n", dtr); |
| 428 | } | 419 | } |
| 420 | |||
| 429 | static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); | 421 | static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); |
| 430 | 422 | ||
| 431 | static ssize_t isl1208_sysfs_show_usr(struct device *dev, | 423 | static ssize_t |
| 432 | struct device_attribute *attr, | 424 | isl1208_sysfs_show_usr(struct device *dev, |
| 433 | char *buf) | 425 | struct device_attribute *attr, char *buf) |
| 434 | { | 426 | { |
| 435 | int usr; | 427 | int usr = isl1208_i2c_get_usr(to_i2c_client(dev)); |
| 436 | |||
| 437 | usr = isl1208_i2c_get_usr(to_i2c_client(dev)); | ||
| 438 | if (usr < 0) | 428 | if (usr < 0) |
| 439 | return usr; | 429 | return usr; |
| 440 | 430 | ||
| 441 | return sprintf(buf, "0x%.4x\n", usr); | 431 | return sprintf(buf, "0x%.4x\n", usr); |
| 442 | } | 432 | } |
| 443 | 433 | ||
| 444 | static ssize_t isl1208_sysfs_store_usr(struct device *dev, | 434 | static ssize_t |
| 445 | struct device_attribute *attr, | 435 | isl1208_sysfs_store_usr(struct device *dev, |
| 446 | const char *buf, size_t count) | 436 | struct device_attribute *attr, |
| 437 | const char *buf, size_t count) | ||
| 447 | { | 438 | { |
| 448 | int usr = -1; | 439 | int usr = -1; |
| 449 | 440 | ||
| @@ -460,124 +451,116 @@ static ssize_t isl1208_sysfs_store_usr(struct device *dev, | |||
| 460 | 451 | ||
| 461 | return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count; | 452 | return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count; |
| 462 | } | 453 | } |
| 454 | |||
| 463 | static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr, | 455 | static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr, |
| 464 | isl1208_sysfs_store_usr); | 456 | isl1208_sysfs_store_usr); |
| 465 | 457 | ||
| 466 | static int | 458 | static int |
| 467 | isl1208_probe(struct i2c_adapter *adapter, int addr, int kind) | 459 | isl1208_sysfs_register(struct device *dev) |
| 468 | { | 460 | { |
| 469 | int rc = 0; | 461 | int err; |
| 470 | struct i2c_client *new_client = NULL; | 462 | |
| 471 | struct rtc_device *rtc = NULL; | 463 | err = device_create_file(dev, &dev_attr_atrim); |
| 464 | if (err) | ||
| 465 | return err; | ||
| 472 | 466 | ||
| 473 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { | 467 | err = device_create_file(dev, &dev_attr_dtrim); |
| 474 | rc = -ENODEV; | 468 | if (err) { |
| 475 | goto failout; | 469 | device_remove_file(dev, &dev_attr_atrim); |
| 470 | return err; | ||
| 476 | } | 471 | } |
| 477 | 472 | ||
| 478 | new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | 473 | err = device_create_file(dev, &dev_attr_usr); |
| 479 | if (new_client == NULL) { | 474 | if (err) { |
| 480 | rc = -ENOMEM; | 475 | device_remove_file(dev, &dev_attr_atrim); |
| 481 | goto failout; | 476 | device_remove_file(dev, &dev_attr_dtrim); |
| 482 | } | 477 | } |
| 483 | 478 | ||
| 484 | new_client->addr = addr; | 479 | return 0; |
| 485 | new_client->adapter = adapter; | 480 | } |
| 486 | new_client->driver = &isl1208_driver; | ||
| 487 | new_client->flags = 0; | ||
| 488 | strcpy(new_client->name, DRV_NAME); | ||
| 489 | 481 | ||
| 490 | if (kind < 0) { | 482 | static int |
| 491 | rc = isl1208_i2c_validate_client(new_client); | 483 | isl1208_sysfs_unregister(struct device *dev) |
| 492 | if (rc < 0) | 484 | { |
| 493 | goto failout; | 485 | device_remove_file(dev, &dev_attr_atrim); |
| 494 | } | 486 | device_remove_file(dev, &dev_attr_atrim); |
| 487 | device_remove_file(dev, &dev_attr_usr); | ||
| 488 | |||
| 489 | return 0; | ||
| 490 | } | ||
| 491 | |||
| 492 | static int | ||
| 493 | isl1208_probe(struct i2c_client *client) | ||
| 494 | { | ||
| 495 | int rc = 0; | ||
| 496 | struct rtc_device *rtc; | ||
| 495 | 497 | ||
| 496 | rc = i2c_attach_client(new_client); | 498 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) |
| 497 | if (rc < 0) | 499 | return -ENODEV; |
| 498 | goto failout; | ||
| 499 | 500 | ||
| 500 | dev_info(&new_client->dev, | 501 | if (isl1208_i2c_validate_client(client) < 0) |
| 502 | return -ENODEV; | ||
| 503 | |||
| 504 | dev_info(&client->dev, | ||
| 501 | "chip found, driver version " DRV_VERSION "\n"); | 505 | "chip found, driver version " DRV_VERSION "\n"); |
| 502 | 506 | ||
| 503 | rtc = rtc_device_register(isl1208_driver.driver.name, | 507 | rtc = rtc_device_register(isl1208_driver.driver.name, |
| 504 | &new_client->dev, | 508 | &client->dev, &isl1208_rtc_ops, |
| 505 | &isl1208_rtc_ops, THIS_MODULE); | 509 | THIS_MODULE); |
| 506 | 510 | if (IS_ERR(rtc)) | |
| 507 | if (IS_ERR(rtc)) { | 511 | return PTR_ERR(rtc); |
| 508 | rc = PTR_ERR(rtc); | ||
| 509 | goto failout_detach; | ||
| 510 | } | ||
| 511 | 512 | ||
| 512 | i2c_set_clientdata(new_client, rtc); | 513 | i2c_set_clientdata(client, rtc); |
| 513 | 514 | ||
| 514 | rc = isl1208_i2c_get_sr(new_client); | 515 | rc = isl1208_i2c_get_sr(client); |
| 515 | if (rc < 0) { | 516 | if (rc < 0) { |
| 516 | dev_err(&new_client->dev, "reading status failed\n"); | 517 | dev_err(&client->dev, "reading status failed\n"); |
| 517 | goto failout_unregister; | 518 | goto exit_unregister; |
| 518 | } | 519 | } |
| 519 | 520 | ||
| 520 | if (rc & ISL1208_REG_SR_RTCF) | 521 | if (rc & ISL1208_REG_SR_RTCF) |
| 521 | dev_warn(&new_client->dev, "rtc power failure detected, " | 522 | dev_warn(&client->dev, "rtc power failure detected, " |
| 522 | "please set clock.\n"); | 523 | "please set clock.\n"); |
| 523 | 524 | ||
| 524 | rc = device_create_file(&new_client->dev, &dev_attr_atrim); | 525 | rc = isl1208_sysfs_register(&client->dev); |
| 525 | if (rc < 0) | 526 | if (rc) |
| 526 | goto failout_unregister; | 527 | goto exit_unregister; |
| 527 | rc = device_create_file(&new_client->dev, &dev_attr_dtrim); | ||
| 528 | if (rc < 0) | ||
| 529 | goto failout_atrim; | ||
| 530 | rc = device_create_file(&new_client->dev, &dev_attr_usr); | ||
| 531 | if (rc < 0) | ||
| 532 | goto failout_dtrim; | ||
| 533 | 528 | ||
| 534 | return 0; | 529 | return 0; |
| 535 | 530 | ||
| 536 | failout_dtrim: | 531 | exit_unregister: |
| 537 | device_remove_file(&new_client->dev, &dev_attr_dtrim); | ||
| 538 | failout_atrim: | ||
| 539 | device_remove_file(&new_client->dev, &dev_attr_atrim); | ||
| 540 | failout_unregister: | ||
| 541 | rtc_device_unregister(rtc); | 532 | rtc_device_unregister(rtc); |
| 542 | failout_detach: | ||
| 543 | i2c_detach_client(new_client); | ||
| 544 | failout: | ||
| 545 | kfree(new_client); | ||
| 546 | return rc; | ||
| 547 | } | ||
| 548 | 533 | ||
| 549 | static int | 534 | return rc; |
| 550 | isl1208_attach_adapter (struct i2c_adapter *adapter) | ||
| 551 | { | ||
| 552 | return i2c_probe(adapter, &addr_data, isl1208_probe); | ||
| 553 | } | 535 | } |
| 554 | 536 | ||
| 555 | static int | 537 | static int |
| 556 | isl1208_detach_client(struct i2c_client *client) | 538 | isl1208_remove(struct i2c_client *client) |
| 557 | { | 539 | { |
| 558 | int rc; | 540 | struct rtc_device *rtc = i2c_get_clientdata(client); |
| 559 | struct rtc_device *const rtc = i2c_get_clientdata(client); | ||
| 560 | |||
| 561 | if (rtc) | ||
| 562 | rtc_device_unregister(rtc); /* do we need to kfree? */ | ||
| 563 | |||
| 564 | rc = i2c_detach_client(client); | ||
| 565 | if (rc) | ||
| 566 | return rc; | ||
| 567 | 541 | ||
| 568 | kfree(client); | 542 | isl1208_sysfs_unregister(&client->dev); |
| 543 | rtc_device_unregister(rtc); | ||
| 569 | 544 | ||
| 570 | return 0; | 545 | return 0; |
| 571 | } | 546 | } |
| 572 | 547 | ||
| 573 | /* module management */ | 548 | static struct i2c_driver isl1208_driver = { |
| 549 | .driver = { | ||
| 550 | .name = "rtc-isl1208", | ||
| 551 | }, | ||
| 552 | .probe = isl1208_probe, | ||
| 553 | .remove = isl1208_remove, | ||
| 554 | }; | ||
| 574 | 555 | ||
| 575 | static int __init isl1208_init(void) | 556 | static int __init |
| 557 | isl1208_init(void) | ||
| 576 | { | 558 | { |
| 577 | return i2c_add_driver(&isl1208_driver); | 559 | return i2c_add_driver(&isl1208_driver); |
| 578 | } | 560 | } |
| 579 | 561 | ||
| 580 | static void __exit isl1208_exit(void) | 562 | static void __exit |
| 563 | isl1208_exit(void) | ||
| 581 | { | 564 | { |
| 582 | i2c_del_driver(&isl1208_driver); | 565 | i2c_del_driver(&isl1208_driver); |
| 583 | } | 566 | } |
