Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: fixes and new functionality for fm3130

- add sanity check for alarm data in fm3130_probe

- fix fm3130_set_alarm.

According to the datasheet, setting match bit '0' indicates that the
corresponding alarm field will be used in the match process

- add operation alarm_irq_enable operation which is responsible for
handling RTC_AIE_ON, RTC_AIE_OFF ioctls

- remove clearing of AF bit after reading rtc/alarm control register:
according to datasheet this bit is cleared anyway when rtc/alarm control
register is read

[akpm@linux-foundation.org: make fm3130_alarm_irq_enable() static, fix comment layout]
Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>
Acked-by: Wan ZongShun <mcuos.com@gmail.com>
Acked-by: Sergey Lapin <slapin@ossfans.org>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Sergey Matyukevich and committed by
Linus Torvalds
f3f99cf3 5824c7e6

+130 -51
+130 -51
drivers/rtc/rtc-fm3130.c
··· 52 52 struct i2c_msg msg[4]; 53 53 struct i2c_client *client; 54 54 struct rtc_device *rtc; 55 + int alarm_valid; 55 56 int data_valid; 56 - int alarm; 57 57 }; 58 58 static const struct i2c_device_id fm3130_id[] = { 59 59 { "fm3130", 0 }, ··· 87 87 dev_dbg(dev, "invalid mode %d\n", mode); 88 88 break; 89 89 } 90 - /* Checking for alarm */ 91 - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { 92 - fm3130->alarm = 1; 93 - fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; 94 - } 90 + 95 91 i2c_smbus_write_byte_data(fm3130->client, 96 92 FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]); 97 93 } ··· 204 208 struct fm3130 *fm3130 = dev_get_drvdata(dev); 205 209 int tmp; 206 210 struct rtc_time *tm = &alrm->time; 211 + 212 + if (!fm3130->alarm_valid) { 213 + /* 214 + * We have invalid alarm in RTC, probably due to battery faults 215 + * or other problems. Return EIO for now, it will allow us to 216 + * set alarm value later instead of error during probing which 217 + * disables device 218 + */ 219 + return -EIO; 220 + } 221 + 207 222 /* read the RTC alarm registers all at once */ 208 223 tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), 209 224 &fm3130->msg[2], 2); ··· 229 222 fm3130->regs[FM3130_ALARM_DATE], 230 223 fm3130->regs[FM3130_ALARM_MONTHS]); 231 224 232 - 233 225 tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F); 234 226 tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F); 235 227 tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F); 236 228 tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F); 237 229 tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F); 230 + 238 231 if (tm->tm_mon > 0) 239 232 tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ 233 + 240 234 dev_dbg(dev, "%s secs=%d, mins=%d, " 241 235 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", 242 236 "read alarm", tm->tm_sec, tm->tm_min, 243 237 tm->tm_hour, tm->tm_mday, 244 238 tm->tm_mon, tm->tm_year, tm->tm_wday); 239 + 240 + /* check if alarm enabled */ 241 + fm3130->regs[FM3130_RTC_CONTROL] = 242 + i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); 243 + 244 + if ((fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AEN) && 245 + (~fm3130->regs[FM3130_RTC_CONTROL] & 246 + FM3130_RTC_CONTROL_BIT_CAL)) { 247 + alrm->enabled = 1; 248 + } 245 249 246 250 return 0; 247 251 } ··· 269 251 tm->tm_hour, tm->tm_mday, 270 252 tm->tm_mon, tm->tm_year, tm->tm_wday); 271 253 272 - if (tm->tm_sec != -1) 273 - fm3130->regs[FM3130_ALARM_SECONDS] = 274 - bin2bcd(tm->tm_sec) | 0x80; 254 + fm3130->regs[FM3130_ALARM_SECONDS] = 255 + (tm->tm_sec != -1) ? bin2bcd(tm->tm_sec) : 0x80; 275 256 276 - if (tm->tm_min != -1) 277 - fm3130->regs[FM3130_ALARM_MINUTES] = 278 - bin2bcd(tm->tm_min) | 0x80; 257 + fm3130->regs[FM3130_ALARM_MINUTES] = 258 + (tm->tm_min != -1) ? bin2bcd(tm->tm_min) : 0x80; 279 259 280 - if (tm->tm_hour != -1) 281 - fm3130->regs[FM3130_ALARM_HOURS] = 282 - bin2bcd(tm->tm_hour) | 0x80; 260 + fm3130->regs[FM3130_ALARM_HOURS] = 261 + (tm->tm_hour != -1) ? bin2bcd(tm->tm_hour) : 0x80; 283 262 284 - if (tm->tm_mday != -1) 285 - fm3130->regs[FM3130_ALARM_DATE] = 286 - bin2bcd(tm->tm_mday) | 0x80; 263 + fm3130->regs[FM3130_ALARM_DATE] = 264 + (tm->tm_mday != -1) ? bin2bcd(tm->tm_mday) : 0x80; 287 265 288 - if (tm->tm_mon != -1) 289 - fm3130->regs[FM3130_ALARM_MONTHS] = 290 - bin2bcd(tm->tm_mon + 1) | 0x80; 266 + fm3130->regs[FM3130_ALARM_MONTHS] = 267 + (tm->tm_mon != -1) ? bin2bcd(tm->tm_mon + 1) : 0x80; 291 268 292 269 dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n", 293 270 fm3130->regs[FM3130_ALARM_SECONDS], ··· 298 285 } 299 286 fm3130->regs[FM3130_RTC_CONTROL] = 300 287 i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); 301 - /* Checking for alarm */ 302 - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { 303 - fm3130->alarm = 1; 304 - fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; 305 - } 288 + 289 + /* enable or disable alarm */ 306 290 if (alrm->enabled) { 307 291 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, 308 292 (fm3130->regs[FM3130_RTC_CONTROL] & ··· 308 298 } else { 309 299 i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, 310 300 fm3130->regs[FM3130_RTC_CONTROL] & 311 - ~(FM3130_RTC_CONTROL_BIT_AEN)); 301 + ~(FM3130_RTC_CONTROL_BIT_CAL) & 302 + ~(FM3130_RTC_CONTROL_BIT_AEN)); 312 303 } 304 + 305 + /* We assume here that data is valid once written */ 306 + if (!fm3130->alarm_valid) 307 + fm3130->alarm_valid = 1; 308 + 313 309 return 0; 310 + } 311 + 312 + static int fm3130_alarm_irq_enable(struct device *dev, unsigned int enabled) 313 + { 314 + struct fm3130 *fm3130 = dev_get_drvdata(dev); 315 + int ret = 0; 316 + 317 + fm3130->regs[FM3130_RTC_CONTROL] = 318 + i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); 319 + 320 + dev_dbg(dev, "alarm_irq_enable: enable=%d, FM3130_RTC_CONTROL=%02x\n", 321 + enabled, fm3130->regs[FM3130_RTC_CONTROL]); 322 + 323 + switch (enabled) { 324 + case 0: /* alarm off */ 325 + ret = i2c_smbus_write_byte_data(fm3130->client, 326 + FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] & 327 + ~(FM3130_RTC_CONTROL_BIT_CAL) & 328 + ~(FM3130_RTC_CONTROL_BIT_AEN)); 329 + break; 330 + case 1: /* alarm on */ 331 + ret = i2c_smbus_write_byte_data(fm3130->client, 332 + FM3130_RTC_CONTROL, (fm3130->regs[FM3130_RTC_CONTROL] & 333 + ~(FM3130_RTC_CONTROL_BIT_CAL)) | 334 + FM3130_RTC_CONTROL_BIT_AEN); 335 + break; 336 + default: 337 + ret = -EINVAL; 338 + break; 339 + } 340 + 341 + return ret; 314 342 } 315 343 316 344 static const struct rtc_class_ops fm3130_rtc_ops = { ··· 356 308 .set_time = fm3130_set_time, 357 309 .read_alarm = fm3130_read_alarm, 358 310 .set_alarm = fm3130_set_alarm, 311 + .alarm_irq_enable = fm3130_alarm_irq_enable, 359 312 }; 360 313 361 314 static struct i2c_driver fm3130_driver; ··· 405 356 fm3130->msg[3].len = FM3130_ALARM_REGS; 406 357 fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS]; 407 358 359 + fm3130->alarm_valid = 0; 408 360 fm3130->data_valid = 0; 409 361 410 362 tmp = i2c_transfer(adapter, fm3130->msg, 4); ··· 419 369 i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL); 420 370 fm3130->regs[FM3130_CAL_CONTROL] = 421 371 i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL); 422 - 423 - /* Checking for alarm */ 424 - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { 425 - fm3130->alarm = 1; 426 - fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; 427 - } 428 372 429 373 /* Disabling calibration mode */ 430 374 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) { ··· 444 400 fm3130->regs[FM3130_CAL_CONTROL] & 445 401 ~(FM3130_CAL_CONTROL_BIT_nOSCEN)); 446 402 447 - /* oscillator fault? clear flag, and warn */ 448 - if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) 403 + /* low battery? clear flag, and warn */ 404 + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) { 405 + i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, 406 + fm3130->regs[FM3130_RTC_CONTROL] & 407 + ~(FM3130_RTC_CONTROL_BIT_LB)); 449 408 dev_warn(&client->dev, "Low battery!\n"); 409 + } 450 410 451 - /* oscillator fault? clear flag, and warn */ 411 + /* check if Power On Reset bit is set */ 452 412 if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) { 453 413 i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, 454 414 fm3130->regs[FM3130_RTC_CONTROL] & 455 415 ~FM3130_RTC_CONTROL_BIT_POR); 456 - dev_warn(&client->dev, "SET TIME!\n"); 416 + dev_dbg(&client->dev, "POR bit is set\n"); 457 417 } 458 418 /* ACS is controlled by alarm */ 459 419 i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80); 460 420 461 - /* TODO */ 462 - /* TODO need to sanity check alarm */ 463 - tmp = fm3130->regs[FM3130_RTC_SECONDS]; 464 - tmp = bcd2bin(tmp & 0x7f); 465 - if (tmp > 60) 466 - goto exit_bad; 421 + /* alarm registers sanity check */ 422 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); 423 + if (tmp > 59) 424 + goto bad_alarm; 425 + 467 426 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); 468 - if (tmp > 60) 469 - goto exit_bad; 427 + if (tmp > 59) 428 + goto bad_alarm; 429 + 430 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f); 431 + if (tmp > 23) 432 + goto bad_alarm; 470 433 471 434 tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); 472 435 if (tmp == 0 || tmp > 31) 473 - goto exit_bad; 436 + goto bad_alarm; 474 437 475 438 tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); 476 439 if (tmp == 0 || tmp > 12) 477 - goto exit_bad; 440 + goto bad_alarm; 478 441 479 - tmp = fm3130->regs[FM3130_RTC_HOURS]; 442 + fm3130->alarm_valid = 1; 443 + 444 + bad_alarm: 445 + 446 + /* clock registers sanity chek */ 447 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); 448 + if (tmp > 59) 449 + goto bad_clock; 450 + 451 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); 452 + if (tmp > 59) 453 + goto bad_clock; 454 + 455 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f); 456 + if (tmp > 23) 457 + goto bad_clock; 458 + 459 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x7); 460 + if (tmp == 0 || tmp > 7) 461 + goto bad_clock; 462 + 463 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f); 464 + if (tmp == 0 || tmp > 31) 465 + goto bad_clock; 466 + 467 + tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); 468 + if (tmp == 0 || tmp > 12) 469 + goto bad_clock; 480 470 481 471 fm3130->data_valid = 1; 482 472 483 - exit_bad: 484 - if (!fm3130->data_valid) 473 + bad_clock: 474 + 475 + if (!fm3130->data_valid || !fm3130->alarm_valid) 485 476 dev_dbg(&client->dev, 486 477 "%s: %02x %02x %02x %02x %02x %02x %02x %02x" 487 478 "%02x %02x %02x %02x %02x %02x %02x\n",