1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * An rtc/i2c driver for the EM Microelectronic EM3027 |
4 | * Copyright 2011 CompuLab, Ltd. |
5 | * |
6 | * Author: Mike Rapoport <mike@compulab.co.il> |
7 | * |
8 | * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it> |
9 | */ |
10 | |
11 | #include <linux/i2c.h> |
12 | #include <linux/rtc.h> |
13 | #include <linux/bcd.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | |
17 | /* Registers */ |
18 | #define EM3027_REG_ON_OFF_CTRL 0x00 |
19 | #define EM3027_REG_IRQ_CTRL 0x01 |
20 | #define EM3027_REG_IRQ_FLAGS 0x02 |
21 | #define EM3027_REG_STATUS 0x03 |
22 | #define EM3027_REG_RST_CTRL 0x04 |
23 | |
24 | #define EM3027_REG_WATCH_SEC 0x08 |
25 | #define EM3027_REG_WATCH_MIN 0x09 |
26 | #define EM3027_REG_WATCH_HOUR 0x0a |
27 | #define EM3027_REG_WATCH_DATE 0x0b |
28 | #define EM3027_REG_WATCH_DAY 0x0c |
29 | #define EM3027_REG_WATCH_MON 0x0d |
30 | #define EM3027_REG_WATCH_YEAR 0x0e |
31 | |
32 | #define EM3027_REG_ALARM_SEC 0x10 |
33 | #define EM3027_REG_ALARM_MIN 0x11 |
34 | #define EM3027_REG_ALARM_HOUR 0x12 |
35 | #define EM3027_REG_ALARM_DATE 0x13 |
36 | #define EM3027_REG_ALARM_DAY 0x14 |
37 | #define EM3027_REG_ALARM_MON 0x15 |
38 | #define EM3027_REG_ALARM_YEAR 0x16 |
39 | |
40 | static struct i2c_driver em3027_driver; |
41 | |
42 | static int em3027_get_time(struct device *dev, struct rtc_time *tm) |
43 | { |
44 | struct i2c_client *client = to_i2c_client(dev); |
45 | |
46 | unsigned char addr = EM3027_REG_WATCH_SEC; |
47 | unsigned char buf[7]; |
48 | |
49 | struct i2c_msg msgs[] = { |
50 | {/* setup read addr */ |
51 | .addr = client->addr, |
52 | .len = 1, |
53 | .buf = &addr |
54 | }, |
55 | {/* read time/date */ |
56 | .addr = client->addr, |
57 | .flags = I2C_M_RD, |
58 | .len = 7, |
59 | .buf = buf |
60 | }, |
61 | }; |
62 | |
63 | /* read time/date registers */ |
64 | if ((i2c_transfer(adap: client->adapter, msgs: &msgs[0], num: 2)) != 2) { |
65 | dev_err(&client->dev, "%s: read error\n" , __func__); |
66 | return -EIO; |
67 | } |
68 | |
69 | tm->tm_sec = bcd2bin(buf[0]); |
70 | tm->tm_min = bcd2bin(buf[1]); |
71 | tm->tm_hour = bcd2bin(buf[2]); |
72 | tm->tm_mday = bcd2bin(buf[3]); |
73 | tm->tm_wday = bcd2bin(buf[4]); |
74 | tm->tm_mon = bcd2bin(buf[5]) - 1; |
75 | tm->tm_year = bcd2bin(buf[6]) + 100; |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int em3027_set_time(struct device *dev, struct rtc_time *tm) |
81 | { |
82 | struct i2c_client *client = to_i2c_client(dev); |
83 | unsigned char buf[8]; |
84 | |
85 | struct i2c_msg msg = { |
86 | .addr = client->addr, |
87 | .len = 8, |
88 | .buf = buf, /* write time/date */ |
89 | }; |
90 | |
91 | buf[0] = EM3027_REG_WATCH_SEC; |
92 | buf[1] = bin2bcd(tm->tm_sec); |
93 | buf[2] = bin2bcd(tm->tm_min); |
94 | buf[3] = bin2bcd(tm->tm_hour); |
95 | buf[4] = bin2bcd(tm->tm_mday); |
96 | buf[5] = bin2bcd(tm->tm_wday); |
97 | buf[6] = bin2bcd(tm->tm_mon + 1); |
98 | buf[7] = bin2bcd(tm->tm_year % 100); |
99 | |
100 | /* write time/date registers */ |
101 | if ((i2c_transfer(adap: client->adapter, msgs: &msg, num: 1)) != 1) { |
102 | dev_err(&client->dev, "%s: write error\n" , __func__); |
103 | return -EIO; |
104 | } |
105 | |
106 | return 0; |
107 | } |
108 | |
109 | static const struct rtc_class_ops em3027_rtc_ops = { |
110 | .read_time = em3027_get_time, |
111 | .set_time = em3027_set_time, |
112 | }; |
113 | |
114 | static int em3027_probe(struct i2c_client *client) |
115 | { |
116 | struct rtc_device *rtc; |
117 | |
118 | if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_I2C)) |
119 | return -ENODEV; |
120 | |
121 | rtc = devm_rtc_device_register(dev: &client->dev, name: em3027_driver.driver.name, |
122 | ops: &em3027_rtc_ops, THIS_MODULE); |
123 | if (IS_ERR(ptr: rtc)) |
124 | return PTR_ERR(ptr: rtc); |
125 | |
126 | i2c_set_clientdata(client, data: rtc); |
127 | |
128 | return 0; |
129 | } |
130 | |
131 | static const struct i2c_device_id em3027_id[] = { |
132 | { "em3027" , 0 }, |
133 | { } |
134 | }; |
135 | MODULE_DEVICE_TABLE(i2c, em3027_id); |
136 | |
137 | #ifdef CONFIG_OF |
138 | static const struct of_device_id em3027_of_match[] = { |
139 | { .compatible = "emmicro,em3027" , }, |
140 | {} |
141 | }; |
142 | MODULE_DEVICE_TABLE(of, em3027_of_match); |
143 | #endif |
144 | |
145 | static struct i2c_driver em3027_driver = { |
146 | .driver = { |
147 | .name = "rtc-em3027" , |
148 | .of_match_table = of_match_ptr(em3027_of_match), |
149 | }, |
150 | .probe = em3027_probe, |
151 | .id_table = em3027_id, |
152 | }; |
153 | |
154 | module_i2c_driver(em3027_driver); |
155 | |
156 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>" ); |
157 | MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver" ); |
158 | MODULE_LICENSE("GPL" ); |
159 | |