Commit ae3551f9cae5727819d02398b588ac14ef0a9cce

Authored by Mike Rapoport
Committed by Linus Torvalds
1 parent f77fbdf952

rtc: add EM3027 rtc driver

Add support for EM Microelectronic EM3027 RTC chip.

Signed-off-by: Mike Rapoport <mike@compulab.co.il>
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>

Showing 3 changed files with 171 additions and 0 deletions Side-by-side Diff

... ... @@ -361,6 +361,15 @@
361 361 This driver can also be built as a module. If so, the module
362 362 will be called rtc-rx8025.
363 363  
  364 +config RTC_DRV_EM3027
  365 + tristate "EM Microelectronic EM3027"
  366 + help
  367 + If you say yes here you get support for the EM
  368 + Microelectronic EM3027 RTC chips.
  369 +
  370 + This driver can also be built as a module. If so, the module
  371 + will be called rtc-em3027.
  372 +
364 373 endif # I2C
365 374  
366 375 comment "SPI RTC drivers"
drivers/rtc/Makefile
... ... @@ -44,6 +44,7 @@
44 44 obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
45 45 obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
46 46 obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
  47 +obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
47 48 obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
48 49 obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
49 50 obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
drivers/rtc/rtc-em3027.c
  1 +/*
  2 + * An rtc/i2c driver for the EM Microelectronic EM3027
  3 + * Copyright 2011 CompuLab, Ltd.
  4 + *
  5 + * Author: Mike Rapoport <mike@compulab.co.il>
  6 + *
  7 + * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it>
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License version 2 as
  11 + * published by the Free Software Foundation.
  12 + */
  13 +
  14 +#include <linux/i2c.h>
  15 +#include <linux/rtc.h>
  16 +#include <linux/bcd.h>
  17 +
  18 +/* Registers */
  19 +#define EM3027_REG_ON_OFF_CTRL 0x00
  20 +#define EM3027_REG_IRQ_CTRL 0x01
  21 +#define EM3027_REG_IRQ_FLAGS 0x02
  22 +#define EM3027_REG_STATUS 0x03
  23 +#define EM3027_REG_RST_CTRL 0x04
  24 +
  25 +#define EM3027_REG_WATCH_SEC 0x08
  26 +#define EM3027_REG_WATCH_MIN 0x09
  27 +#define EM3027_REG_WATCH_HOUR 0x0a
  28 +#define EM3027_REG_WATCH_DATE 0x0b
  29 +#define EM3027_REG_WATCH_DAY 0x0c
  30 +#define EM3027_REG_WATCH_MON 0x0d
  31 +#define EM3027_REG_WATCH_YEAR 0x0e
  32 +
  33 +#define EM3027_REG_ALARM_SEC 0x10
  34 +#define EM3027_REG_ALARM_MIN 0x11
  35 +#define EM3027_REG_ALARM_HOUR 0x12
  36 +#define EM3027_REG_ALARM_DATE 0x13
  37 +#define EM3027_REG_ALARM_DAY 0x14
  38 +#define EM3027_REG_ALARM_MON 0x15
  39 +#define EM3027_REG_ALARM_YEAR 0x16
  40 +
  41 +static struct i2c_driver em3027_driver;
  42 +
  43 +static int em3027_get_time(struct device *dev, struct rtc_time *tm)
  44 +{
  45 + struct i2c_client *client = to_i2c_client(dev);
  46 +
  47 + unsigned char addr = EM3027_REG_WATCH_SEC;
  48 + unsigned char buf[7];
  49 +
  50 + struct i2c_msg msgs[] = {
  51 + {client->addr, 0, 1, &addr}, /* setup read addr */
  52 + {client->addr, I2C_M_RD, 7, buf}, /* read time/date */
  53 + };
  54 +
  55 + /* read time/date registers */
  56 + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
  57 + dev_err(&client->dev, "%s: read error\n", __func__);
  58 + return -EIO;
  59 + }
  60 +
  61 + tm->tm_sec = bcd2bin(buf[0]);
  62 + tm->tm_min = bcd2bin(buf[1]);
  63 + tm->tm_hour = bcd2bin(buf[2]);
  64 + tm->tm_mday = bcd2bin(buf[3]);
  65 + tm->tm_wday = bcd2bin(buf[4]);
  66 + tm->tm_mon = bcd2bin(buf[5]);
  67 + tm->tm_year = bcd2bin(buf[6]) + 100;
  68 +
  69 + return 0;
  70 +}
  71 +
  72 +static int em3027_set_time(struct device *dev, struct rtc_time *tm)
  73 +{
  74 + struct i2c_client *client = to_i2c_client(dev);
  75 + unsigned char buf[8];
  76 +
  77 + struct i2c_msg msg = {
  78 + client->addr, 0, 8, buf, /* write time/date */
  79 + };
  80 +
  81 + buf[0] = EM3027_REG_WATCH_SEC;
  82 + buf[1] = bin2bcd(tm->tm_sec);
  83 + buf[2] = bin2bcd(tm->tm_min);
  84 + buf[3] = bin2bcd(tm->tm_hour);
  85 + buf[4] = bin2bcd(tm->tm_mday);
  86 + buf[5] = bin2bcd(tm->tm_wday);
  87 + buf[6] = bin2bcd(tm->tm_mon);
  88 + buf[7] = bin2bcd(tm->tm_year % 100);
  89 +
  90 + /* write time/date registers */
  91 + if ((i2c_transfer(client->adapter, &msg, 1)) != 1) {
  92 + dev_err(&client->dev, "%s: write error\n", __func__);
  93 + return -EIO;
  94 + }
  95 +
  96 + return 0;
  97 +}
  98 +
  99 +static const struct rtc_class_ops em3027_rtc_ops = {
  100 + .read_time = em3027_get_time,
  101 + .set_time = em3027_set_time,
  102 +};
  103 +
  104 +static int em3027_probe(struct i2c_client *client,
  105 + const struct i2c_device_id *id)
  106 +{
  107 + struct rtc_device *rtc;
  108 +
  109 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
  110 + return -ENODEV;
  111 +
  112 + rtc = rtc_device_register(em3027_driver.driver.name, &client->dev,
  113 + &em3027_rtc_ops, THIS_MODULE);
  114 + if (IS_ERR(rtc))
  115 + return PTR_ERR(rtc);
  116 +
  117 + i2c_set_clientdata(client, rtc);
  118 +
  119 + return 0;
  120 +}
  121 +
  122 +static int em3027_remove(struct i2c_client *client)
  123 +{
  124 + struct rtc_device *rtc = i2c_get_clientdata(client);
  125 +
  126 + if (rtc)
  127 + rtc_device_unregister(rtc);
  128 +
  129 + return 0;
  130 +}
  131 +
  132 +static struct i2c_device_id em3027_id[] = {
  133 + { "em3027", 0 },
  134 + { }
  135 +};
  136 +
  137 +static struct i2c_driver em3027_driver = {
  138 + .driver = {
  139 + .name = "rtc-em3027",
  140 + },
  141 + .probe = &em3027_probe,
  142 + .remove = &em3027_remove,
  143 + .id_table = em3027_id,
  144 +};
  145 +
  146 +static int __init em3027_init(void)
  147 +{
  148 + return i2c_add_driver(&em3027_driver);
  149 +}
  150 +
  151 +static void __exit em3027_exit(void)
  152 +{
  153 + i2c_del_driver(&em3027_driver);
  154 +}
  155 +
  156 +MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
  157 +MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver");
  158 +MODULE_LICENSE("GPL");
  159 +
  160 +module_init(em3027_init);
  161 +module_exit(em3027_exit);