diff options
author | Mike Rapoport <mike@compulab.co.il> | 2011-05-26 19:25:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-26 20:12:33 -0400 |
commit | ae3551f9cae5727819d02398b588ac14ef0a9cce (patch) | |
tree | 51f1da1007420faef6f242c38fe9db4b8b54092c /drivers/rtc | |
parent | f77fbdf952d81ae20911edccea16693f9fb7c5a0 (diff) |
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>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-em3027.c | 161 |
3 files changed, 171 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 3db52f01d458..512b40ea32cd 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -361,6 +361,15 @@ config RTC_DRV_RX8025 | |||
361 | This driver can also be built as a module. If so, the module | 361 | This driver can also be built as a module. If so, the module |
362 | will be called rtc-rx8025. | 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 | endif # I2C | 373 | endif # I2C |
365 | 374 | ||
366 | comment "SPI RTC drivers" | 375 | comment "SPI RTC drivers" |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 986f17e51df8..4801a0af7bcd 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -44,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o | |||
44 | obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o | 44 | obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o |
45 | obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o | 45 | obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o |
46 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o | 46 | obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o |
47 | obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o | ||
47 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 48 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
48 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o | 49 | obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o |
49 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o | 50 | obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o |
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c new file mode 100644 index 000000000000..d8e1c2578553 --- /dev/null +++ b/drivers/rtc/rtc-em3027.c | |||
@@ -0,0 +1,161 @@ | |||
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); | ||