123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- /*
- * rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip.
- *
- * Copyright (C) 2008 Sergey Lapin
- * Based on ds1307 driver by James Chapman and David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include <linux/module.h>
- #include <linux/i2c.h>
- #include <linux/rtc.h>
- #include <linux/bcd.h>
- #include <linux/slab.h>
- #define FM3130_RTC_CONTROL (0x0)
- #define FM3130_CAL_CONTROL (0x1)
- #define FM3130_RTC_SECONDS (0x2)
- #define FM3130_RTC_MINUTES (0x3)
- #define FM3130_RTC_HOURS (0x4)
- #define FM3130_RTC_DAY (0x5)
- #define FM3130_RTC_DATE (0x6)
- #define FM3130_RTC_MONTHS (0x7)
- #define FM3130_RTC_YEARS (0x8)
- #define FM3130_ALARM_SECONDS (0x9)
- #define FM3130_ALARM_MINUTES (0xa)
- #define FM3130_ALARM_HOURS (0xb)
- #define FM3130_ALARM_DATE (0xc)
- #define FM3130_ALARM_MONTHS (0xd)
- #define FM3130_ALARM_WP_CONTROL (0xe)
- #define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */
- #define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */
- #define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */
- #define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */
- #define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */
- #define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */
- #define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */
- #define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* W=1 -> write mode W=0 normal */
- #define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* R=1 -> read mode R=0 normal */
- #define FM3130_CLOCK_REGS 7
- #define FM3130_ALARM_REGS 5
- struct fm3130 {
- u8 reg_addr_time;
- u8 reg_addr_alarm;
- u8 regs[15];
- struct i2c_msg msg[4];
- struct i2c_client *client;
- struct rtc_device *rtc;
- int alarm_valid;
- int data_valid;
- };
- static const struct i2c_device_id fm3130_id[] = {
- { "fm3130", 0 },
- { }
- };
- MODULE_DEVICE_TABLE(i2c, fm3130_id);
- #define FM3130_MODE_NORMAL 0
- #define FM3130_MODE_WRITE 1
- #define FM3130_MODE_READ 2
- static void fm3130_rtc_mode(struct device *dev, int mode)
- {
- struct fm3130 *fm3130 = dev_get_drvdata(dev);
- fm3130->regs[FM3130_RTC_CONTROL] =
- i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
- switch (mode) {
- case FM3130_MODE_NORMAL:
- fm3130->regs[FM3130_RTC_CONTROL] &=
- ~(FM3130_RTC_CONTROL_BIT_WRITE |
- FM3130_RTC_CONTROL_BIT_READ);
- break;
- case FM3130_MODE_WRITE:
- fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_WRITE;
- break;
- case FM3130_MODE_READ:
- fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_READ;
- break;
- default:
- dev_dbg(dev, "invalid mode %d\n", mode);
- break;
- }
- i2c_smbus_write_byte_data(fm3130->client,
- FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]);
- }
- static int fm3130_get_time(struct device *dev, struct rtc_time *t)
- {
- struct fm3130 *fm3130 = dev_get_drvdata(dev);
- int tmp;
- if (!fm3130->data_valid) {
- /* We have invalid data in RTC, probably due
- to battery faults or other problems. Return EIO
- for now, it will allow us to set data later instead
- of error during probing which disables device */
- return -EIO;
- }
- fm3130_rtc_mode(dev, FM3130_MODE_READ);
- /* read the RTC date and time registers all at once */
- tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
- fm3130->msg, 2);
- if (tmp != 2) {
- dev_err(dev, "%s error %d\n", "read", tmp);
- return -EIO;
- }
- fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
- dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs);
- t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
- t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
- tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f;
- t->tm_hour = bcd2bin(tmp);
- t->tm_wday = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1;
- t->tm_mday = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
- tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f;
- t->tm_mon = bcd2bin(tmp) - 1;
- /* assume 20YY not 19YY, and ignore CF bit */
- t->tm_year = bcd2bin(fm3130->regs[FM3130_RTC_YEARS]) + 100;
- dev_dbg(dev, "%s secs=%d, mins=%d, "
- "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
- "read", t->tm_sec, t->tm_min,
- t->tm_hour, t->tm_mday,
- t->tm_mon, t->tm_year, t->tm_wday);
- return 0;
- }
- static int fm3130_set_time(struct device *dev, struct rtc_time *t)
- {
- struct fm3130 *fm3130 = dev_get_drvdata(dev);
- int tmp, i;
- u8 *buf = fm3130->regs;
- dev_dbg(dev, "%s secs=%d, mins=%d, "
- "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
- "write", t->tm_sec, t->tm_min,
- t->tm_hour, t->tm_mday,
- t->tm_mon, t->tm_year, t->tm_wday);
- /* first register addr */
- buf[FM3130_RTC_SECONDS] = bin2bcd(t->tm_sec);
- buf[FM3130_RTC_MINUTES] = bin2bcd(t->tm_min);
- buf[FM3130_RTC_HOURS] = bin2bcd(t->tm_hour);
- buf[FM3130_RTC_DAY] = bin2bcd(t->tm_wday + 1);
- buf[FM3130_RTC_DATE] = bin2bcd(t->tm_mday);
- buf[FM3130_RTC_MONTHS] = bin2bcd(t->tm_mon + 1);
- /* assume 20YY not 19YY */
- tmp = t->tm_year - 100;
- buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
- dev_dbg(dev, "%s: %15ph\n", "write", buf);
- fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
- /* Writing time registers, we don't support multibyte transfers */
- for (i = 0; i < FM3130_CLOCK_REGS; i++) {
- i2c_smbus_write_byte_data(fm3130->client,
- FM3130_RTC_SECONDS + i,
- fm3130->regs[FM3130_RTC_SECONDS + i]);
- }
- fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
- /* We assume here that data are valid once written */
- if (!fm3130->data_valid)
- fm3130->data_valid = 1;
- return 0;
- }
- static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
- {
- struct fm3130 *fm3130 = dev_get_drvdata(dev);
- int tmp;
- struct rtc_time *tm = &alrm->time;
- if (!fm3130->alarm_valid) {
- /*
- * We have invalid alarm in RTC, probably due to battery faults
- * or other problems. Return EIO for now, it will allow us to
- * set alarm value later instead of error during probing which
- * disables device
- */
- return -EIO;
- }
- /* read the RTC alarm registers all at once */
- tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
- &fm3130->msg[2], 2);
- if (tmp != 2) {
- dev_err(dev, "%s error %d\n", "read", tmp);
- return -EIO;
- }
- dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n",
- fm3130->regs[FM3130_ALARM_SECONDS],
- fm3130->regs[FM3130_ALARM_MINUTES],
- fm3130->regs[FM3130_ALARM_HOURS],
- fm3130->regs[FM3130_ALARM_DATE],
- fm3130->regs[FM3130_ALARM_MONTHS]);
- tm->tm_sec = bcd2bin(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
- tm->tm_min = bcd2bin(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
- tm->tm_hour = bcd2bin(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
- tm->tm_mday = bcd2bin(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
- tm->tm_mon = bcd2bin(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
- if (tm->tm_mon > 0)
- tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
- dev_dbg(dev, "%s secs=%d, mins=%d, "
- "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
- "read alarm", tm->tm_sec, tm->tm_min,
- tm->tm_hour, tm->tm_mday,
- tm->tm_mon, tm->tm_year, tm->tm_wday);
- /* check if alarm enabled */
- fm3130->regs[FM3130_RTC_CONTROL] =
- i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
- if ((fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AEN) &&
- (~fm3130->regs[FM3130_RTC_CONTROL] &
- FM3130_RTC_CONTROL_BIT_CAL)) {
- alrm->enabled = 1;
- }
- return 0;
- }
- static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
- {
- struct fm3130 *fm3130 = dev_get_drvdata(dev);
- struct rtc_time *tm = &alrm->time;
- int i;
- dev_dbg(dev, "%s secs=%d, mins=%d, "
- "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
- "write alarm", tm->tm_sec, tm->tm_min,
- tm->tm_hour, tm->tm_mday,
- tm->tm_mon, tm->tm_year, tm->tm_wday);
- fm3130->regs[FM3130_ALARM_SECONDS] =
- (tm->tm_sec != -1) ? bin2bcd(tm->tm_sec) : 0x80;
- fm3130->regs[FM3130_ALARM_MINUTES] =
- (tm->tm_min != -1) ? bin2bcd(tm->tm_min) : 0x80;
- fm3130->regs[FM3130_ALARM_HOURS] =
- (tm->tm_hour != -1) ? bin2bcd(tm->tm_hour) : 0x80;
- fm3130->regs[FM3130_ALARM_DATE] =
- (tm->tm_mday != -1) ? bin2bcd(tm->tm_mday) : 0x80;
- fm3130->regs[FM3130_ALARM_MONTHS] =
- (tm->tm_mon != -1) ? bin2bcd(tm->tm_mon + 1) : 0x80;
- dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n",
- fm3130->regs[FM3130_ALARM_SECONDS],
- fm3130->regs[FM3130_ALARM_MINUTES],
- fm3130->regs[FM3130_ALARM_HOURS],
- fm3130->regs[FM3130_ALARM_DATE],
- fm3130->regs[FM3130_ALARM_MONTHS]);
- /* Writing time registers, we don't support multibyte transfers */
- for (i = 0; i < FM3130_ALARM_REGS; i++) {
- i2c_smbus_write_byte_data(fm3130->client,
- FM3130_ALARM_SECONDS + i,
- fm3130->regs[FM3130_ALARM_SECONDS + i]);
- }
- fm3130->regs[FM3130_RTC_CONTROL] =
- i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
- /* enable or disable alarm */
- if (alrm->enabled) {
- i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
- (fm3130->regs[FM3130_RTC_CONTROL] &
- ~(FM3130_RTC_CONTROL_BIT_CAL)) |
- FM3130_RTC_CONTROL_BIT_AEN);
- } else {
- i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
- fm3130->regs[FM3130_RTC_CONTROL] &
- ~(FM3130_RTC_CONTROL_BIT_CAL) &
- ~(FM3130_RTC_CONTROL_BIT_AEN));
- }
- /* We assume here that data is valid once written */
- if (!fm3130->alarm_valid)
- fm3130->alarm_valid = 1;
- return 0;
- }
- static int fm3130_alarm_irq_enable(struct device *dev, unsigned int enabled)
- {
- struct fm3130 *fm3130 = dev_get_drvdata(dev);
- int ret = 0;
- fm3130->regs[FM3130_RTC_CONTROL] =
- i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
- dev_dbg(dev, "alarm_irq_enable: enable=%d, FM3130_RTC_CONTROL=%02x\n",
- enabled, fm3130->regs[FM3130_RTC_CONTROL]);
- switch (enabled) {
- case 0: /* alarm off */
- ret = i2c_smbus_write_byte_data(fm3130->client,
- FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL] &
- ~(FM3130_RTC_CONTROL_BIT_CAL) &
- ~(FM3130_RTC_CONTROL_BIT_AEN));
- break;
- case 1: /* alarm on */
- ret = i2c_smbus_write_byte_data(fm3130->client,
- FM3130_RTC_CONTROL, (fm3130->regs[FM3130_RTC_CONTROL] &
- ~(FM3130_RTC_CONTROL_BIT_CAL)) |
- FM3130_RTC_CONTROL_BIT_AEN);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static const struct rtc_class_ops fm3130_rtc_ops = {
- .read_time = fm3130_get_time,
- .set_time = fm3130_set_time,
- .read_alarm = fm3130_read_alarm,
- .set_alarm = fm3130_set_alarm,
- .alarm_irq_enable = fm3130_alarm_irq_enable,
- };
- static struct i2c_driver fm3130_driver;
- static int fm3130_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct fm3130 *fm3130;
- int err = -ENODEV;
- int tmp;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- if (!i2c_check_functionality(adapter,
- I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
- return -EIO;
- fm3130 = devm_kzalloc(&client->dev, sizeof(struct fm3130), GFP_KERNEL);
- if (!fm3130)
- return -ENOMEM;
- fm3130->client = client;
- i2c_set_clientdata(client, fm3130);
- fm3130->reg_addr_time = FM3130_RTC_SECONDS;
- fm3130->reg_addr_alarm = FM3130_ALARM_SECONDS;
- /* Messages to read time */
- fm3130->msg[0].addr = client->addr;
- fm3130->msg[0].flags = 0;
- fm3130->msg[0].len = 1;
- fm3130->msg[0].buf = &fm3130->reg_addr_time;
- fm3130->msg[1].addr = client->addr;
- fm3130->msg[1].flags = I2C_M_RD;
- fm3130->msg[1].len = FM3130_CLOCK_REGS;
- fm3130->msg[1].buf = &fm3130->regs[FM3130_RTC_SECONDS];
- /* Messages to read alarm */
- fm3130->msg[2].addr = client->addr;
- fm3130->msg[2].flags = 0;
- fm3130->msg[2].len = 1;
- fm3130->msg[2].buf = &fm3130->reg_addr_alarm;
- fm3130->msg[3].addr = client->addr;
- fm3130->msg[3].flags = I2C_M_RD;
- fm3130->msg[3].len = FM3130_ALARM_REGS;
- fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS];
- fm3130->alarm_valid = 0;
- fm3130->data_valid = 0;
- tmp = i2c_transfer(adapter, fm3130->msg, 4);
- if (tmp != 4) {
- dev_dbg(&client->dev, "read error %d\n", tmp);
- err = -EIO;
- goto exit_free;
- }
- fm3130->regs[FM3130_RTC_CONTROL] =
- i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL);
- fm3130->regs[FM3130_CAL_CONTROL] =
- i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL);
- /* Disabling calibration mode */
- if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) {
- i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
- fm3130->regs[FM3130_RTC_CONTROL] &
- ~(FM3130_RTC_CONTROL_BIT_CAL));
- dev_warn(&client->dev, "Disabling calibration mode!\n");
- }
- /* Disabling read and write modes */
- if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE ||
- fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) {
- i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
- fm3130->regs[FM3130_RTC_CONTROL] &
- ~(FM3130_RTC_CONTROL_BIT_READ |
- FM3130_RTC_CONTROL_BIT_WRITE));
- dev_warn(&client->dev, "Disabling READ or WRITE mode!\n");
- }
- /* oscillator off? turn it on, so clock can tick. */
- if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN)
- i2c_smbus_write_byte_data(client, FM3130_CAL_CONTROL,
- fm3130->regs[FM3130_CAL_CONTROL] &
- ~(FM3130_CAL_CONTROL_BIT_nOSCEN));
- /* low battery? clear flag, and warn */
- if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) {
- i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
- fm3130->regs[FM3130_RTC_CONTROL] &
- ~(FM3130_RTC_CONTROL_BIT_LB));
- dev_warn(&client->dev, "Low battery!\n");
- }
- /* check if Power On Reset bit is set */
- if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) {
- i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
- fm3130->regs[FM3130_RTC_CONTROL] &
- ~FM3130_RTC_CONTROL_BIT_POR);
- dev_dbg(&client->dev, "POR bit is set\n");
- }
- /* ACS is controlled by alarm */
- i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80);
- /* alarm registers sanity check */
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
- if (tmp > 59)
- goto bad_alarm;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
- if (tmp > 59)
- goto bad_alarm;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f);
- if (tmp > 23)
- goto bad_alarm;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
- if (tmp == 0 || tmp > 31)
- goto bad_alarm;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
- if (tmp == 0 || tmp > 12)
- goto bad_alarm;
- fm3130->alarm_valid = 1;
- bad_alarm:
- /* clock registers sanity chek */
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
- if (tmp > 59)
- goto bad_clock;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
- if (tmp > 59)
- goto bad_clock;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_HOURS] & 0x3f);
- if (tmp > 23)
- goto bad_clock;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_DAY] & 0x7);
- if (tmp == 0 || tmp > 7)
- goto bad_clock;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
- if (tmp == 0 || tmp > 31)
- goto bad_clock;
- tmp = bcd2bin(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
- if (tmp == 0 || tmp > 12)
- goto bad_clock;
- fm3130->data_valid = 1;
- bad_clock:
- if (!fm3130->data_valid || !fm3130->alarm_valid)
- dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers",
- fm3130->regs);
- /* We won't bail out here because we just got invalid data.
- Time setting from u-boot doesn't work anyway */
- fm3130->rtc = devm_rtc_device_register(&client->dev, client->name,
- &fm3130_rtc_ops, THIS_MODULE);
- if (IS_ERR(fm3130->rtc)) {
- err = PTR_ERR(fm3130->rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
- goto exit_free;
- }
- return 0;
- exit_free:
- return err;
- }
- static struct i2c_driver fm3130_driver = {
- .driver = {
- .name = "rtc-fm3130",
- },
- .probe = fm3130_probe,
- .id_table = fm3130_id,
- };
- module_i2c_driver(fm3130_driver);
- MODULE_DESCRIPTION("RTC driver for FM3130");
- MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
- MODULE_LICENSE("GPL");
|