nvmem: rockchip-efuse: add support for rk3288 secure efuse
[firefly-linux-kernel-4.4.55.git] / drivers / rtc / rtc-m41t66.c
1 /*\r
2  * I2C client/driver for the ST M41T62 family of i2c rtc chips.\r
3  *\r
4  * Author: lhh <lhh@rock-chips.com>\r
5  *Port to rk29 by yxj\r
6  *\r
7  * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com>\r
8  *\r
9  * 2010 (c) rockchip\r
10  *\r
11  * This program is free software; you can redistribute it and/or modify\r
12  * it under the terms of the GNU General Public License version 2 as\r
13  * published by the Free Software Foundation.\r
14  *\r
15  */\r
16 \r
17 #include <linux/bcd.h>\r
18 #include <linux/i2c.h>\r
19 #include <linux/init.h>\r
20 #include <linux/kernel.h>\r
21 #include <linux/module.h>\r
22 #include <linux/rtc.h>\r
23 #include <linux/slab.h>\r
24 #include <linux/smp_lock.h>\r
25 #include <linux/string.h>\r
26 \r
27 \r
28 #include <linux/i2c.h>\r
29 #include <linux/bcd.h>\r
30 #include <linux/rtc.h>\r
31 #include <linux/delay.h>\r
32 #include <linux/wakelock.h>\r
33 #include <mach/gpio.h>\r
34 #include <mach/iomux.h>\r
35 \r
36 \r
37 \r
38 \r
39 #define M41T62_REG_SSEC 0\r
40 #define M41T62_REG_SEC  1\r
41 #define M41T62_REG_MIN  2\r
42 #define M41T62_REG_HOUR 3\r
43 #define M41T62_REG_SQWDAY       4\r
44 #define M41T62_REG_DAY  5\r
45 #define M41T62_REG_MON  6\r
46 #define M41T62_REG_YEAR 7\r
47 #define M41T62_REG_ALARM_MON    0xa\r
48 #define M41T62_REG_ALARM_DAY    0xb\r
49 #define M41T62_REG_ALARM_HOUR   0xc\r
50 #define M41T62_REG_ALARM_MIN    0xd\r
51 #define M41T62_REG_ALARM_SEC    0xe\r
52 #define M41T62_REG_FLAGS        0xf\r
53 #define M41T62_REG_SQW  0x13\r
54 \r
55 #define M41T62_REG_SEC_INDEX                    (M41T62_REG_SEC - 1)\r
56 #define M41T62_REG_MIN_INDEX                    (M41T62_REG_MIN - 1)\r
57 #define M41T62_REG_HOUR_INDEX                   (M41T62_REG_HOUR - 1)\r
58 #define M41T62_REG_SQWDAY_INDEX                         (M41T62_REG_SQWDAY - 1)\r
59 #define M41T62_REG_DAY_INDEX                    (M41T62_REG_DAY - 1)\r
60 #define M41T62_REG_MON_INDEX                    (M41T62_REG_MON - 1)\r
61 #define M41T62_REG_YEAR_INDEX                   (M41T62_REG_YEAR - 1)\r
62 \r
63 #define M41T62_DATETIME_REG_SIZE                (M41T62_REG_YEAR )\r
64 \r
65 #define M41T62_REG_ALARM_MON_INDEX      (M41T62_REG_ALARM_MON-0x0a)\r
66 #define M41T62_REG_ALARM_DAY_INDEX      (M41T62_REG_ALARM_DAY-0x0a)\r
67 #define M41T62_REG_ALARM_HOUR_INDEX      (M41T62_REG_ALARM_HOUR-0x0a)\r
68 #define M41T62_REG_ALARM_MIN_INDEX      (M41T62_REG_ALARM_MIN-0x0a)\r
69 #define M41T62_REG_ALARM_SEC_INDEX      (M41T62_REG_ALARM_SEC-0x0a)\r
70 #define M41T62_REG_FLAGS_INDEX      (M41T62_REG_FLAGS-0x0a)\r
71 \r
72 \r
73 #define M41T62_ALARM_REG_SIZE   \\r
74         (M41T62_REG_FLAGS + 1 - M41T62_REG_ALARM_MON)\r
75         \r
76 \r
77 #define M41T62_SEC_ST           (1 << 7)        /* ST: Stop Bit */\r
78 #define M41T62_ALMON_AFE        (1 << 7)        /* AFE: alarm flag Enable Bit */\r
79 #define M41T62_ALMON_SQWE       (1 << 6)        /* SQWE: SQW Enable Bit */\r
80 //#define M41T62_ALHOUR_HT      (1 << 6)        /* HT: Halt Update Bit */\r
81 #define M41T62_FLAGS_AF         (1 << 6)        /* AF: Alarm Flag Bit */\r
82 //#define M41T62_FLAGS_BATT_LOW (1 << 4)        /* BL: Battery Low Bit */\r
83 #define M41T62_WATCHDOG_RB2     (1 << 7)        /* RB: Watchdog resolution */\r
84 #define M41T62_WATCHDOG_RB1     (1 << 1)        /* RB: Watchdog resolution */\r
85 #define M41T62_WATCHDOG_RB0     (1 << 0)        /* RB: Watchdog resolution */\r
86 \r
87 //#define M41T62_FEATURE_HT     (1 << 0)        /* Halt feature */\r
88 //#define M41T62_FEATURE_BL     (1 << 1)        /* Battery low indicator */\r
89 //#define M41T62_FEATURE_SQ     (1 << 2)        /* Squarewave feature */\r
90 //#define M41T62_FEATURE_WD     (1 << 3)        /* Extra watchdog resolution */\r
91 //#define M41T62_FEATURE_SQ_ALT (1 << 4)        /* RSx bits are in reg 4 */\r
92 \r
93 #define REPEAT_SEC              5\r
94 #define REPEAT_MIN              4\r
95 #define REPEAT_HOUR     3\r
96 #define REPEAT_DAY              2\r
97 #define REPEAT_MON      1\r
98 #define REPEAT_YEAR     0\r
99 #define RTC_SPEED       100 * 1000\r
100 \r
101 \r
102 \r
103 #define DRV_VERSION "0.05"\r
104 #define DRV_NAME  "rtc-M41T66"\r
105 #if 1\r
106 #define DBG   printk//(x...)    printk(KERN_INFO  "rtc-M41T62:" x)\r
107 #else\r
108 #define DBG(x...)\r
109 #endif\r
110 \r
111 //static struct semaphore rtc_sem;//Ryan\r
112 \r
113 \r
114 struct rock_rtc {\r
115         int irq;\r
116         struct i2c_client *client;\r
117         struct work_struct work;\r
118         struct mutex mutex;\r
119         struct rtc_device *rtc;\r
120         int exiting;\r
121         struct rtc_wkalrm alarm;\r
122         struct wake_lock wake_lock;\r
123 };\r
124 \r
125 \r
126 static int rtc_alarm_repeat_set(int mod)\r
127 {\r
128         return 0;\r
129 }\r
130 \r
131 \r
132 static irqreturn_t rtc_wakeup_irq(int irq, void *dev_id)\r
133 {       \r
134         struct rock_rtc *rk_rtc = (struct rock_rtc *)dev_id;\r
135         DBG("enter %s\n",__func__);\r
136         disable_irq_nosync(irq);\r
137         schedule_work(&rk_rtc->work);\r
138         return IRQ_HANDLED;\r
139 }\r
140 \r
141 \r
142 static int m41t62_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], unsigned len)\r
143 {\r
144         int ret; \r
145         \r
146         \r
147         ret = i2c_master_reg8_recv(client, reg, buf, len, RTC_SPEED);\r
148         if(ret < 0 )\r
149         {\r
150                 printk("%s:rtc m41t62 read reg error\n\n\n",__func__);\r
151         }\r
152 \r
153         return ret; \r
154 }\r
155 \r
156 static int m41t62_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], __u16 len)\r
157 {\r
158         int ret; \r
159         ret = i2c_master_reg8_send(client, reg, buf, (int)len, RTC_SPEED);\r
160         if(ret < 0)\r
161         {\r
162                 printk("%s error>>>>>\n",__func__);\r
163         }\r
164         return ret;\r
165 }\r
166 \r
167 static int m41t62_init_device(struct i2c_client *client)\r
168 {\r
169         //DBG("%s\n",__func__);\r
170 \r
171         u8 alarmbuf[M41T62_ALARM_REG_SIZE];\r
172         u8 sqwdayreg;\r
173         \r
174         //read alarm register current value\r
175         m41t62_i2c_read_regs(client,M41T62_REG_ALARM_MON,alarmbuf,M41T62_ALARM_REG_SIZE);\r
176         \r
177 \r
178         /*DBG("init alarm mon=0x%x, day=0x%x, hour=0x%x, min=0x%x, sec=0x%x, flags=0x%x\n",\r
179                         alarmbuf[M41T62_REG_ALARM_MON_INDEX],\r
180                         alarmbuf[M41T62_REG_ALARM_DAY_INDEX],\r
181                         alarmbuf[M41T62_REG_ALARM_HOUR_INDEX],\r
182                         alarmbuf[M41T62_REG_ALARM_MIN_INDEX],\r
183                         alarmbuf[M41T62_REG_ALARM_SEC_INDEX],\r
184                         alarmbuf[M41T62_REG_FLAGS_INDEX]);*/\r
185 \r
186         //clear alarm register\r
187         alarmbuf[M41T62_REG_ALARM_MON_INDEX] &= ~(0x1f | M41T62_ALMON_AFE);\r
188         alarmbuf[M41T62_REG_ALARM_DAY_INDEX] = 0;\r
189         alarmbuf[M41T62_REG_ALARM_HOUR_INDEX] = 0;\r
190         alarmbuf[M41T62_REG_ALARM_MIN_INDEX] = 0;\r
191         alarmbuf[M41T62_REG_ALARM_SEC_INDEX] = 0;\r
192         alarmbuf[M41T62_REG_FLAGS_INDEX] = 0;\r
193 \r
194         //write alarm register\r
195         m41t62_i2c_set_regs(client,M41T62_REG_ALARM_MON,alarmbuf,M41T62_ALARM_REG_SIZE);\r
196 \r
197         //set outclk to 32768HZ\r
198         m41t62_i2c_read_regs(client,M41T62_REG_SQWDAY,&sqwdayreg,1);\r
199         sqwdayreg =(sqwdayreg|0x10)&0x1f;\r
200         m41t62_i2c_set_regs(client,M41T62_REG_SQWDAY,&sqwdayreg,1);\r
201         //m41t62_i2c_read_regs(client,M41T62_REG_SQWDAY,&sqwdayreg,1);\r
202         //printk("sqwdayreg:0x%x\n",sqwdayreg);\r
203         #if 0\r
204         sqwdayreg =0;\r
205         m41t62_i2c_read_regs(client,M41T62_REG_FLAGS,&sqwdayreg,1);  //YLZ++\r
206         \r
207         printk("%s:rtc m41t2 flag_reg = 0x%x\n",__func__,sqwdayreg);\r
208      //  if(sqwdayreg & 0x04)\r
209        {\r
210 \r
211                 m41t62_i2c_read_regs(client,M41T62_REG_SEC,&sqwdayreg,1);  //YLZ++\r
212                 printk("%s:rtc m41t2 sec_reg = 0x%x\n",__func__,sqwdayreg);\r
213         sqwdayreg |= 0x80; \r
214         m41t62_i2c_set_regs(client,M41T62_REG_SEC,&sqwdayreg,1);\r
215                 sqwdayreg =0x7f; \r
216                 m41t62_i2c_set_regs(client,M41T62_REG_SEC,&sqwdayreg,1);\r
217                 m41t62_i2c_read_regs(client,M41T62_REG_SEC,&sqwdayreg,1);  //YLZ++\r
218                 printk("%s:rtc m41t2 sec_reg = 0x%x\n",__func__,sqwdayreg);\r
219 \r
220 \r
221        }\r
222         sqwdayreg =0;\r
223         m41t62_i2c_read_regs(client,M41T62_REG_FLAGS,&sqwdayreg,1);  //YLZ++\r
224         printk("%s:rtc m41t2 atfer flag_reg = 0x%x\n",__func__,sqwdayreg);\r
225       #endif\r
226 \r
227         return 0;\r
228 }\r
229 \r
230 static int m41t62_get_datetime(struct i2c_client *client,\r
231                                struct rtc_time *tm)\r
232 {\r
233 \r
234         \r
235         struct rock_rtc *rk_rtc = i2c_get_clientdata(client);   \r
236         u8 datetime[M41T62_DATETIME_REG_SIZE];\r
237         int ret = 0;\r
238 \r
239         mutex_lock(&rk_rtc->mutex);\r
240         ret = m41t62_i2c_read_regs(client,M41T62_REG_SEC,datetime,M41T62_DATETIME_REG_SIZE);\r
241         if(ret < 0)\r
242         {\r
243                 printk("%s:read date time from rtc m41t2 error\n",__func__);\r
244         }\r
245         else\r
246         {\r
247           ret = 0;\r
248         }\r
249         mutex_unlock(&rk_rtc->mutex);\r
250         /*DBG("-------M41T62_REG_SEC=%x--",datetime[M41T62_REG_SEC_INDEX]);\r
251         DBG("-------M41T62_REG_MIN=%x--",datetime[M41T62_REG_MIN_INDEX]);\r
252         DBG("-------M41T62_REG_HOUR=%x--",datetime[M41T62_REG_HOUR_INDEX]);\r
253         DBG("-------M41T62_REG_SQWDAY=%x--",datetime[M41T62_REG_SQWDAY_INDEX]);\r
254         DBG("-------M41T62_REG_DAY=%x--",datetime[M41T62_REG_DAY_INDEX]);\r
255         DBG("-------M41T62_REG_MON=%x--",datetime[M41T62_REG_MON_INDEX]);\r
256         DBG("-------M41T62_REG_YEAR=%x--",datetime[M41T62_REG_YEAR_INDEX]);*/\r
257         \r
258         tm->tm_sec = bcd2bin(datetime[M41T62_REG_SEC_INDEX]& 0x7f);\r
259         tm->tm_min = bcd2bin(datetime[M41T62_REG_MIN_INDEX] & 0x7f);\r
260         tm->tm_hour = bcd2bin(datetime[M41T62_REG_HOUR_INDEX] & 0x3f);\r
261         tm->tm_mday = bcd2bin(datetime[M41T62_REG_DAY_INDEX] & 0x3f);\r
262         tm->tm_wday = bcd2bin(datetime[M41T62_REG_SQWDAY_INDEX] & 0x07);\r
263         tm->tm_mon = bcd2bin(datetime[M41T62_REG_MON_INDEX] & 0x1f) - 1;\r
264         // assume 20YY not 19YY, and ignore the Century Bit \r
265         tm->tm_year = bcd2bin(datetime[M41T62_REG_YEAR_INDEX]) + 100;\r
266     DBG("%s>>>>%4d-%02d-%02d>>wday:%d>>%02d:%02d:%02d>>\n",\r
267                 __func__,tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_wday,\r
268                 tm->tm_hour,tm->tm_min,tm->tm_sec);\r
269         \r
270         if(tm->tm_year < 100)\r
271         {\r
272                 printk(KERN_INFO "%s:the time read from the rtc M41T62 is illegal ,\\r
273                         we will use the default time:2010.8.2\n",__func__);\r
274                 tm->tm_sec = 1;\r
275                 tm->tm_min = 7;\r
276                 tm->tm_hour = 7;\r
277                 tm->tm_mday = 2;\r
278                 tm->tm_wday = 4;\r
279                 tm->tm_mon = 7;\r
280                 tm->tm_year = 110;\r
281         }\r
282 \r
283         \r
284         return ret;\r
285 }\r
286 \r
287 /* Sets the given date and time to the real time clock. */\r
288 static int m41t62_set_datetime(struct i2c_client *client, struct rtc_time *tm)\r
289 {\r
290         \r
291         struct rock_rtc *rk_rtc = i2c_get_clientdata(client);   \r
292         int ret = 0;\r
293         u8 datetime[M41T62_DATETIME_REG_SIZE];\r
294         \r
295         datetime[M41T62_REG_SEC_INDEX] = bin2bcd(tm->tm_sec);\r
296         datetime[M41T62_REG_MIN_INDEX] = bin2bcd(tm->tm_min);\r
297         datetime[M41T62_REG_HOUR_INDEX] =bin2bcd(tm->tm_hour) ;\r
298         datetime[M41T62_REG_SQWDAY_INDEX] =(tm->tm_wday & 0x07) |0x10;\r
299         datetime[M41T62_REG_DAY_INDEX] = bin2bcd(tm->tm_mday);\r
300         datetime[M41T62_REG_MON_INDEX] = bin2bcd(tm->tm_mon + 1) ;\r
301         /* assume 20YY not 19YY */\r
302         datetime[M41T62_REG_YEAR_INDEX] = bin2bcd(tm->tm_year % 100);\r
303         printk(KERN_INFO "%s:set time %4d-%02d-%02d %02d:%02d:%02d to rtc \n",__func__,\r
304                 tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);\r
305         \r
306         mutex_lock(&rk_rtc->mutex);\r
307         ret = m41t62_i2c_set_regs(client,M41T62_REG_SEC,datetime, M41T62_DATETIME_REG_SIZE);\r
308         if(ret < 0)\r
309         {\r
310                 printk(KERN_INFO "%s:set time to rtc m41t62 error\n",__func__);\r
311         }\r
312         else\r
313         {\r
314                 ret = 0;\r
315         }\r
316         \r
317         mutex_unlock(&rk_rtc->mutex);\r
318         \r
319         return ret;\r
320 }\r
321 \r
322 static int m41t62_rtc_read_time(struct device *dev, struct rtc_time *tm)\r
323 {\r
324         //DBG("%s>>>>>>>>>>>\n",__func__);\r
325         return m41t62_get_datetime(to_i2c_client(dev), tm);\r
326 }\r
327 \r
328 static int m41t62_rtc_set_time(struct device *dev, struct rtc_time *tm)\r
329 {\r
330         //DBG("%s\n",__func__);\r
331         return m41t62_set_datetime(to_i2c_client(dev), tm);\r
332 }\r
333 \r
334 #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)\r
335 static int m41t62_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)\r
336 {\r
337         int rc;\r
338         struct i2c_client *client = to_i2c_client(dev);\r
339         \r
340         DBG("%s>>>>>>>>>%d\n",__func__ ,cmd);\r
341         switch (cmd) {\r
342         case RTC_AIE_OFF:\r
343         case RTC_AIE_ON:\r
344                 break;\r
345         default:\r
346                 DBG("RTC func m41t62_rtc_ioctl -ENOIOCTLCMD\n");\r
347                 return -ENOIOCTLCMD;\r
348         }\r
349         DBG("RTC func m41t62_rtc_ioctl 1\n");\r
350         rc = i2c_smbus_read_byte_data(client, M41T62_REG_ALARM_MON);\r
351         if (rc < 0)\r
352                 goto err;\r
353         switch (cmd) {\r
354         case RTC_AIE_OFF:\r
355                 rc &= ~M41T62_ALMON_AFE;\r
356                 break;\r
357         case RTC_AIE_ON:\r
358                 rc |= M41T62_ALMON_AFE;\r
359                 break;\r
360         }\r
361         DBG("\n@@@@@@@@@@@RTC func m41t62_rtc_ioctl 2@@@@@@@@@@@@@\n");\r
362         if (i2c_smbus_write_byte_data(client, M41T62_REG_ALARM_MON, rc) < 0)\r
363                 goto err;\r
364         DBG("\n@@@@@@@@@@@RTC func m41t62_rtc_ioctl 3@@@@@@@@@@@@@\n");\r
365         return 0;\r
366 err:\r
367         return -EIO;\r
368 }\r
369 #else\r
370 #define m41t62_rtc_ioctl NULL\r
371 #endif\r
372 \r
373 static int m41t62_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)\r
374 {\r
375         //DBG("%s>>>>>>>>>>>>\n",__func__);\r
376         struct i2c_client *client = to_i2c_client(dev);\r
377         struct rock_rtc *rk_rtc = i2c_get_clientdata(client);\r
378         struct rtc_time current_time ;\r
379         u8 alarmbuf[M41T62_ALARM_REG_SIZE];\r
380         int ret = 0;\r
381         \r
382 \r
383         \r
384         mutex_lock(&rk_rtc->mutex);\r
385         //read the current value of alarm register\r
386         m41t62_i2c_read_regs(client,M41T62_REG_ALARM_MON,alarmbuf, M41T62_ALARM_REG_SIZE);\r
387         mutex_unlock(&rk_rtc->mutex);\r
388 \r
389         //clear alarm register \r
390         alarmbuf[M41T62_REG_ALARM_MON_INDEX] &= ~(0x1f | M41T62_ALMON_AFE);\r
391         alarmbuf[M41T62_REG_ALARM_DAY_INDEX] = 0;\r
392         alarmbuf[M41T62_REG_ALARM_HOUR_INDEX] &= ~(0x3f | 0x80);\r
393         alarmbuf[M41T62_REG_ALARM_MIN_INDEX] = 0;\r
394         alarmbuf[M41T62_REG_ALARM_SEC_INDEX] = 0;\r
395 \r
396 \r
397         rk_rtc->alarm = *alarm;\r
398         DBG("time write to alarm :%4d-%02d-%02d %02d:%02d:%02d>>enable:%d\n",\r
399                         alarm->time.tm_year+1900,\r
400                         alarm->time.tm_mon,\r
401                         alarm->time.tm_mday,\r
402                         alarm->time.tm_hour,\r
403                         alarm->time.tm_min,\r
404                         alarm->time.tm_sec,\r
405                         alarm->enabled);\r
406         //get current time\r
407         m41t62_get_datetime(client,&current_time);\r
408         DBG("current time   :%4d-%02d-%02d %02d:%02d:%02d>>\n",\r
409                         current_time.tm_year+1900,\r
410                         current_time.tm_mon,\r
411                         current_time.tm_mday,\r
412                         current_time.tm_hour,\r
413                         current_time.tm_min,\r
414                         current_time.tm_sec);\r
415    \r
416         /* offset into rtc's regs */\r
417         alarmbuf[M41T62_REG_ALARM_SEC_INDEX] |= alarm->time.tm_sec >= 0 ?bin2bcd(alarm->time.tm_sec) : 0x80;\r
418         alarmbuf[M41T62_REG_ALARM_MIN_INDEX] |= alarm->time.tm_min >= 0 ?bin2bcd(alarm->time.tm_min) : 0x80;\r
419         alarmbuf[M41T62_REG_ALARM_HOUR_INDEX] |= alarm->time.tm_hour >= 0 ?bin2bcd(alarm->time.tm_hour) : 0x80;\r
420         alarmbuf[M41T62_REG_ALARM_DAY_INDEX] |= alarm->time.tm_mday >= 0 ?bin2bcd(alarm->time.tm_mday) : 0x80;\r
421         if (alarm->time.tm_mon >= 0)\r
422                 alarmbuf[M41T62_REG_ALARM_MON_INDEX] |= bin2bcd(alarm->time.tm_mon + 1);\r
423         else\r
424                 alarmbuf[M41T62_REG_ALARM_DAY_INDEX] |= 0x40;\r
425 \r
426         //Ryan@...\r
427         //DBG("enable mon day");\r
428         alarmbuf[M41T62_REG_ALARM_MON_INDEX] |= M41T62_ALMON_AFE ;\r
429         alarmbuf[M41T62_REG_ALARM_DAY_INDEX] |= 0xc0;//mon, day repeat\r
430         //reg[M41T62_REG_ALARM_HOUR] |= 0x80;//hour repeat\r
431         //reg[M41T62_REG_ALARM_MIN] |= 0x80;//min repeat\r
432         \r
433         \r
434         \r
435 \r
436         //write alarm register \r
437         mutex_lock(&rk_rtc->mutex);\r
438         ret = m41t62_i2c_set_regs(client,M41T62_REG_ALARM_MON,alarmbuf, M41T62_DATETIME_REG_SIZE);\r
439         if(ret < 0)\r
440         {\r
441                 printk(KERN_INFO "%s:set rtc m41t62 alarm error\n",__func__);\r
442         }\r
443         else\r
444         {\r
445          ret  = 0;\r
446         }\r
447         \r
448         \r
449         mutex_unlock(&rk_rtc->mutex);\r
450         return ret;\r
451         \r
452 }\r
453 \r
454 static int m41t62_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)\r
455 {\r
456         //DBG("%s>>>>>>>>>>>>>\n",__func__);\r
457         \r
458         struct i2c_client *client = to_i2c_client(dev);\r
459         struct rock_rtc *rk_rtc = i2c_get_clientdata(client);\r
460         u8 alarmreg[M41T62_ALARM_REG_SIZE ]; // all alarm regs and flags \r
461         int ret = 0;\r
462         \r
463         \r
464         mutex_lock(&rk_rtc->mutex);\r
465         m41t62_i2c_read_regs(client,M41T62_REG_ALARM_MON,alarmreg, M41T62_ALARM_REG_SIZE);\r
466         mutex_unlock(&rk_rtc->mutex);\r
467         \r
468         //printk("read alarm mon=0x%x, day=0x%x, hour=0x%x, min=0x%x, sec=0x%x, flags=0x%x\n",\r
469         //              reg[M41T62_REG_ALARM_MON],\r
470         //              reg[M41T62_REG_ALARM_DAY],\r
471         //              reg[M41T62_REG_ALARM_HOUR],\r
472         //              reg[M41T62_REG_ALARM_MIN],\r
473         //              reg[M41T62_REG_ALARM_SEC],\r
474         //              reg[M41T62_REG_FLAGS]); \r
475         t->time.tm_sec = -1;\r
476         t->time.tm_min = -1;\r
477         t->time.tm_hour = -1;\r
478         t->time.tm_mday = -1;\r
479         t->time.tm_mon = -1;\r
480         if (!(alarmreg[M41T62_REG_ALARM_SEC_INDEX] & 0x80))\r
481                 t->time.tm_sec = bcd2bin(alarmreg[M41T62_REG_ALARM_SEC_INDEX] & 0x7f);\r
482         if (!(alarmreg[M41T62_REG_ALARM_MIN_INDEX] & 0x80))\r
483                 t->time.tm_min = bcd2bin(alarmreg[M41T62_REG_ALARM_MIN_INDEX] & 0x7f);\r
484         if (!(alarmreg[M41T62_REG_ALARM_HOUR_INDEX] & 0x80))\r
485                 t->time.tm_hour = bcd2bin(alarmreg[M41T62_REG_ALARM_HOUR_INDEX] & 0x3f);\r
486         if (!(alarmreg[M41T62_REG_ALARM_DAY_INDEX] & 0x80))\r
487                 t->time.tm_mday = bcd2bin(alarmreg[M41T62_REG_ALARM_DAY_INDEX] & 0x3f);\r
488         if (!(alarmreg[M41T62_REG_ALARM_DAY_INDEX] & 0x40))\r
489                 t->time.tm_mon = bcd2bin(alarmreg[M41T62_REG_ALARM_MON_INDEX] & 0x1f) - 1;\r
490         t->time.tm_year = -1;\r
491         t->time.tm_wday = -1;\r
492         t->time.tm_yday = -1;\r
493         t->time.tm_isdst = -1;\r
494         t->enabled = !!(alarmreg[M41T62_REG_ALARM_MON_INDEX] & M41T62_ALMON_AFE);\r
495         t->pending = !!(alarmreg[M41T62_REG_FLAGS_INDEX] & M41T62_FLAGS_AF);\r
496 \r
497         \r
498         mutex_lock(&rk_rtc->mutex);\r
499         ret = m41t62_i2c_read_regs(client,M41T62_REG_ALARM_MON,alarmreg, M41T62_ALARM_REG_SIZE );\r
500         if(ret < 0)\r
501         {\r
502                 printk(KERN_INFO "%s:read rtc m41t62 alarm error\n",__func__);\r
503         }\r
504         else\r
505         {\r
506                 ret = 0;\r
507         }\r
508         mutex_unlock(&rk_rtc->mutex);\r
509         //printk("read alarm2 mon=0x%x, day=0x%x, hour=0x%x, min=0x%x, sec=0x%x, flags=0x%x\n",\r
510         //              reg[M41T62_REG_ALARM_MON],\r
511         //              reg[M41T62_REG_ALARM_DAY],\r
512         //              reg[M41T62_REG_ALARM_HOUR],\r
513         //              reg[M41T62_REG_ALARM_MIN],\r
514         //              reg[M41T62_REG_ALARM_SEC],\r
515         //              reg[M41T62_REG_FLAGS]); \r
516 \r
517         \r
518         return ret;\r
519 }\r
520 \r
521 static void rockrtc_work_func(struct work_struct *work)\r
522 {       \r
523         struct rock_rtc *rk_rtc = container_of(work, struct rock_rtc, work);\r
524         struct i2c_client *client = rk_rtc->client;\r
525         struct rtc_time now;\r
526         u8 flagreg;\r
527 \r
528         DBG("enter %s\n",__func__);\r
529 \r
530         mutex_lock(&rk_rtc->mutex);\r
531         m41t62_i2c_read_regs(client,M41T62_REG_FLAGS,&flagreg, 1 );\r
532         flagreg &=~M41T62_FLAGS_AF ;\r
533         m41t62_i2c_set_regs(client,M41T62_REG_FLAGS,&flagreg, 1 );\r
534         mutex_unlock(&rk_rtc->mutex);\r
535 \r
536         m41t62_get_datetime(client ,&now);\r
537         mutex_lock(&rk_rtc->mutex);\r
538         if (rk_rtc->alarm.enabled && rk_rtc->alarm.time.tm_sec > now.tm_sec)\r
539         {\r
540                 long timeout = rk_rtc->alarm.time.tm_sec - now.tm_sec + 1;\r
541                 pr_info("stay awake %lds\n", timeout);\r
542                 wake_lock_timeout(&rk_rtc->wake_lock, timeout * HZ);\r
543         }\r
544         if (!rk_rtc->exiting)\r
545                 enable_irq(rk_rtc->irq);\r
546         mutex_unlock(&rk_rtc->mutex);\r
547 }\r
548 \r
549 \r
550 static struct rtc_class_ops m41t62_rtc_ops = {\r
551         .read_time = m41t62_rtc_read_time,\r
552         .set_time = m41t62_rtc_set_time,\r
553         .read_alarm = m41t62_rtc_read_alarm,\r
554         .set_alarm = m41t62_rtc_set_alarm,\r
555         .ioctl = m41t62_rtc_ioctl,\r
556 };\r
557 \r
558 #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)\r
559 static ssize_t m41t62_sysfs_show_flags(struct device *dev,\r
560                                 struct device_attribute *attr, char *buf)\r
561 {\r
562         struct i2c_client *client = to_i2c_client(dev);\r
563         int val;\r
564 \r
565         val = i2c_smbus_read_byte_data(client, M41T62_REG_FLAGS);\r
566         if (val < 0)\r
567                 return -EIO;\r
568         return sprintf(buf, "%#x\n", val);\r
569 }\r
570 static DEVICE_ATTR(flags, S_IRUGO, m41t62_sysfs_show_flags, NULL);\r
571 \r
572 static ssize_t m41t62_sysfs_show_sqwfreq(struct device *dev,\r
573                                 struct device_attribute *attr, char *buf)\r
574 {\r
575         struct i2c_client *client = to_i2c_client(dev);\r
576         int val;\r
577 \r
578         val = i2c_smbus_read_byte_data(client, M41T62_REG_SQW);\r
579         if (val < 0)\r
580                 return -EIO;\r
581         val = (val >> 4) & 0xf;\r
582         switch (val) {\r
583         case 0:\r
584                 break;\r
585         case 1:\r
586                 val = 32768;\r
587                 break;\r
588         default:\r
589                 val = 32768 >> val;\r
590         }\r
591         return sprintf(buf, "%d\n", val);\r
592 }\r
593 static ssize_t m41t62_sysfs_set_sqwfreq(struct device *dev,\r
594                                 struct device_attribute *attr,\r
595                                 const char *buf, size_t count)\r
596 {\r
597         struct i2c_client *client = to_i2c_client(dev);\r
598         int almon, sqw;\r
599         int val = simple_strtoul(buf, NULL, 0);\r
600 \r
601         if (val) {\r
602                 if (!is_power_of_2(val))\r
603                         return -EINVAL;\r
604                 val = ilog2(val);\r
605                 if (val == 15)\r
606                         val = 1;\r
607                 else if (val < 14)\r
608                         val = 15 - val;\r
609                 else\r
610                         return -EINVAL;\r
611         }\r
612         /* disable SQW, set SQW frequency & re-enable */\r
613         almon = i2c_smbus_read_byte_data(client, M41T62_REG_ALARM_MON);\r
614         if (almon < 0)\r
615                 return -EIO;\r
616         sqw = i2c_smbus_read_byte_data(client, M41T62_REG_SQW);\r
617         if (sqw < 0)\r
618                 return -EIO;\r
619         sqw = (sqw & 0x0f) | (val << 4);\r
620         if (i2c_smbus_write_byte_data(client, M41T62_REG_ALARM_MON,\r
621                                       almon & ~M41T62_ALMON_SQWE) < 0 ||\r
622             i2c_smbus_write_byte_data(client, M41T62_REG_SQW, sqw) < 0)\r
623                 return -EIO;\r
624         if (val && i2c_smbus_write_byte_data(client, M41T62_REG_ALARM_MON,\r
625                                              almon | M41T62_ALMON_SQWE) < 0)\r
626                 return -EIO;\r
627         return count;\r
628 }\r
629 static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR,\r
630                    m41t62_sysfs_show_sqwfreq, m41t62_sysfs_set_sqwfreq);\r
631 \r
632 static struct attribute *attrs[] = {\r
633         &dev_attr_flags.attr,\r
634         &dev_attr_sqwfreq.attr,\r
635         NULL,\r
636 };\r
637 static struct attribute_group attr_group = {\r
638         .attrs = attrs,\r
639 };\r
640 \r
641 static int m41t62_sysfs_register(struct device *dev)\r
642 {\r
643         DBG("\n@@@@@@@@@@@m41t62_sysfs_register@@@@@@@@@@@@@\n");\r
644         return sysfs_create_group(&dev->kobj, &attr_group);\r
645 }\r
646 #else\r
647 static int m41t62_sysfs_register(struct device *dev)\r
648 {\r
649         DBG("\n@@@@@@@@@@@m41t62_sysfs_register@@@@@@@@@@@@@\n");\r
650         return 0;\r
651 }\r
652 #endif\r
653 \r
654 \r
655 \r
656 \r
657 /*\r
658  *****************************************************************************\r
659  *\r
660  *      Driver Interface\r
661  *\r
662  *****************************************************************************\r
663  */\r
664 static int __devinit m41t62_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
665 {\r
666         printk("%s>>>>>>>>>>>>>client->flags:%d\n",__func__,client->flags);\r
667         int rc = 0;\r
668         struct rock_rtc *rk_rtc = NULL;\r
669         struct rtc_device *rtc = NULL;\r
670         struct rtc_time tm_read, tm = {\r
671         .tm_year = 111,\r
672         .tm_mon = 2,\r
673         .tm_mday = 7,\r
674         .tm_wday = 7,\r
675         .tm_hour = 12, \r
676         .tm_min = 1,\r
677         .tm_sec = 8\r
678         };      \r
679         \r
680         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ){\r
681                 rc = -ENODEV;\r
682                 printk("i2c_check_functionality fail\n");\r
683                 goto exit;\r
684         }  \r
685         \r
686         rk_rtc = kzalloc(sizeof(struct rock_rtc), GFP_KERNEL);\r
687         if (!rk_rtc) {\r
688                 return -ENOMEM;\r
689         }\r
690         \r
691         rtc = rtc_device_register(client->name, &client->dev,\r
692                                   &m41t62_rtc_ops, THIS_MODULE);\r
693         if (IS_ERR(rtc)) {\r
694                 rc = PTR_ERR(rtc);\r
695                 rtc = NULL;\r
696                 printk("\nm41t62_probe err3\n");\r
697                 goto exit;\r
698         }\r
699         \r
700         rk_rtc->client = client;\r
701         rk_rtc->rtc = rtc;\r
702         \r
703         mutex_init(&rk_rtc->mutex);\r
704         wake_lock_init(&rk_rtc->wake_lock, WAKE_LOCK_SUSPEND, "rtc_m41t62");\r
705         INIT_WORK(&rk_rtc->work, rockrtc_work_func);\r
706         \r
707         i2c_set_clientdata(client, rk_rtc);\r
708         \r
709         rc = m41t62_sysfs_register(&client->dev);\r
710         if (rc)\r
711         {\r
712                 printk("\nm41t62_probe err4\n");\r
713                 goto exit;\r
714         }\r
715 \r
716         \r
717         m41t62_init_device(client);//0323\r
718         m41t62_get_datetime(client, &tm_read);  \r
719         if((tm_read.tm_year < 111 ) |(tm_read.tm_year > 120 ) |(tm_read.tm_mon > 11))   \r
720         {\r
721                 m41t62_set_datetime(client, &tm);\r
722                 printk("%s [%d]run set time \n",__FUNCTION__,__LINE__);         \r
723         }\r
724 \r
725         if(gpio_request(client->irq, "rtc gpio"))\r
726         {\r
727                 dev_err(&client->dev, "gpio request fail\n");\r
728                 gpio_free(client->irq);\r
729                 goto exit;\r
730         }\r
731         \r
732         rk_rtc->irq = gpio_to_irq(client->irq);\r
733         gpio_pull_updown(client->irq,GPIOPullUp);\r
734         if (request_irq(rk_rtc->irq, rtc_wakeup_irq, IRQF_TRIGGER_FALLING, client->dev.driver->name, rk_rtc) < 0)\r
735         {\r
736                 printk("unable to request rtc irq\n");\r
737                 goto exit;\r
738         }       \r
739         enable_irq_wake(rk_rtc->irq);\r
740         \r
741         return 0;\r
742         \r
743 exit:\r
744         if (rtc)\r
745                 rtc_device_unregister(rtc);\r
746         if (rk_rtc)\r
747                 kfree(rk_rtc);\r
748         return rc;\r
749 \r
750 }\r
751 \r
752 \r
753 \r
754 static int __devexit m41t62_remove(struct i2c_client *client)\r
755 {\r
756         \r
757         struct rock_rtc  *rk_rtc = i2c_get_clientdata(client);\r
758         \r
759                 if (rk_rtc->irq > 0) {\r
760                         mutex_lock(&rk_rtc->mutex);\r
761                         rk_rtc->exiting = 1;\r
762                         mutex_unlock(&rk_rtc->mutex);\r
763         \r
764                         free_irq(rk_rtc->irq, rk_rtc);\r
765                         cancel_work_sync(&rk_rtc->work);\r
766                 }\r
767         \r
768                 rtc_device_unregister(rk_rtc->rtc);\r
769                 wake_lock_destroy(&rk_rtc->wake_lock);\r
770                 kfree(rk_rtc);\r
771                 rk_rtc = NULL;\r
772         \r
773         return 0;\r
774 }\r
775 \r
776 static const struct i2c_device_id m41t62_id[] = {\r
777         { DRV_NAME, 0 },\r
778         { }\r
779 };\r
780 MODULE_DEVICE_TABLE(i2c, m41t62_id);\r
781 \r
782 \r
783 static struct i2c_driver m41t62_driver = {\r
784         .driver = {\r
785                 .name = DRV_NAME,\r
786                 .owner  = THIS_MODULE,\r
787         },\r
788         .probe          = m41t62_probe,\r
789         .remove         = __devexit_p(m41t62_remove),\r
790         .id_table       = m41t62_id,\r
791         \r
792 };\r
793 \r
794 \r
795 static int __init m41t62_rtc_init(void)\r
796 {\r
797         int ret;\r
798         \r
799         printk("%s\n",__func__);\r
800         ret = i2c_add_driver(&m41t62_driver);\r
801         printk("%s:return = %d\n",__func__,ret);\r
802         return ret;\r
803 }\r
804 \r
805 static void __exit m41t62_rtc_exit(void)\r
806 {\r
807         DBG("%s>>>>>>>>>\n",__func__);\r
808         i2c_del_driver(&m41t62_driver);\r
809 }\r
810 \r
811 MODULE_AUTHOR("rockchip lhh");\r
812 MODULE_DESCRIPTION("ST Microelectronics M41T62 series RTC I2C Client Driver");\r
813 MODULE_LICENSE("GPL");\r
814 MODULE_VERSION(DRV_VERSION);\r
815 \r
816 module_init(m41t62_rtc_init);\r
817 module_exit(m41t62_rtc_exit);\r