OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [rtc/] [rtc-isl1208.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Intersil ISL1208 rtc class driver
3
 *
4
 * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org>
5
 *
6
 *  This program is free software; you can redistribute  it and/or modify it
7
 *  under  the terms of  the GNU General  Public License as published by the
8
 *  Free Software Foundation;  either version 2 of the  License, or (at your
9
 *  option) any later version.
10
 *
11
 */
12
 
13
#include <linux/module.h>
14
#include <linux/i2c.h>
15
#include <linux/bcd.h>
16
#include <linux/rtc.h>
17
 
18
#define DRV_NAME "isl1208"
19
#define DRV_VERSION "0.2"
20
 
21
/* Register map */
22
/* rtc section */
23
#define ISL1208_REG_SC  0x00
24
#define ISL1208_REG_MN  0x01
25
#define ISL1208_REG_HR  0x02
26
#define ISL1208_REG_HR_MIL     (1<<7) /* 24h/12h mode */
27
#define ISL1208_REG_HR_PM      (1<<5) /* PM/AM bit in 12h mode */
28
#define ISL1208_REG_DT  0x03
29
#define ISL1208_REG_MO  0x04
30
#define ISL1208_REG_YR  0x05
31
#define ISL1208_REG_DW  0x06
32
#define ISL1208_RTC_SECTION_LEN 7
33
 
34
/* control/status section */
35
#define ISL1208_REG_SR  0x07
36
#define ISL1208_REG_SR_ARST    (1<<7) /* auto reset */
37
#define ISL1208_REG_SR_XTOSCB  (1<<6) /* crystal oscillator */
38
#define ISL1208_REG_SR_WRTC    (1<<4) /* write rtc */
39
#define ISL1208_REG_SR_ALM     (1<<2) /* alarm */
40
#define ISL1208_REG_SR_BAT     (1<<1) /* battery */
41
#define ISL1208_REG_SR_RTCF    (1<<0) /* rtc fail */
42
#define ISL1208_REG_INT 0x08
43
#define ISL1208_REG_09  0x09 /* reserved */
44
#define ISL1208_REG_ATR 0x0a
45
#define ISL1208_REG_DTR 0x0b
46
 
47
/* alarm section */
48
#define ISL1208_REG_SCA 0x0c
49
#define ISL1208_REG_MNA 0x0d
50
#define ISL1208_REG_HRA 0x0e
51
#define ISL1208_REG_DTA 0x0f
52
#define ISL1208_REG_MOA 0x10
53
#define ISL1208_REG_DWA 0x11
54
#define ISL1208_ALARM_SECTION_LEN 6
55
 
56
/* user section */
57
#define ISL1208_REG_USR1 0x12
58
#define ISL1208_REG_USR2 0x13
59
#define ISL1208_USR_SECTION_LEN 2
60
 
61
/* i2c configuration */
62
#define ISL1208_I2C_ADDR 0xde
63
 
64
static unsigned short normal_i2c[] = {
65
        ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
66
};
67
I2C_CLIENT_INSMOD; /* defines addr_data */
68
 
69
static int isl1208_attach_adapter(struct i2c_adapter *adapter);
70
static int isl1208_detach_client(struct i2c_client *client);
71
 
72
static struct i2c_driver isl1208_driver = {
73
        .driver         = {
74
                .name   = DRV_NAME,
75
        },
76
        .id             = I2C_DRIVERID_ISL1208,
77
        .attach_adapter = &isl1208_attach_adapter,
78
        .detach_client  = &isl1208_detach_client,
79
};
80
 
81
/* block read */
82
static int
83
isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
84
                       unsigned len)
85
{
86
        u8 reg_addr[1] = { reg };
87
        struct i2c_msg msgs[2] = {
88
                { client->addr, client->flags, sizeof(reg_addr), reg_addr },
89
                { client->addr, client->flags | I2C_M_RD, len, buf }
90
        };
91
        int ret;
92
 
93
        BUG_ON(len == 0);
94
        BUG_ON(reg > ISL1208_REG_USR2);
95
        BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
96
 
97
        ret = i2c_transfer(client->adapter, msgs, 2);
98
        if (ret > 0)
99
                ret = 0;
100
        return ret;
101
}
102
 
103
/* block write */
104
static int
105
isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
106
                       unsigned len)
107
{
108
        u8 i2c_buf[ISL1208_REG_USR2 + 2];
109
        struct i2c_msg msgs[1] = {
110
                { client->addr, client->flags, len + 1, i2c_buf }
111
        };
112
        int ret;
113
 
114
        BUG_ON(len == 0);
115
        BUG_ON(reg > ISL1208_REG_USR2);
116
        BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
117
 
118
        i2c_buf[0] = reg;
119
        memcpy(&i2c_buf[1], &buf[0], len);
120
 
121
        ret = i2c_transfer(client->adapter, msgs, 1);
122
        if (ret > 0)
123
                ret = 0;
124
        return ret;
125
}
126
 
127
/* simple check to see wether we have a isl1208 */
128
static int isl1208_i2c_validate_client(struct i2c_client *client)
129
{
130
        u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
131
        u8 zero_mask[ISL1208_RTC_SECTION_LEN] = {
132
                0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8
133
        };
134
        int i;
135
        int ret;
136
 
137
        ret = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
138
        if (ret < 0)
139
                return ret;
140
 
141
        for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) {
142
                if (regs[i] & zero_mask[i]) /* check if bits are cleared */
143
                        return -ENODEV;
144
        }
145
 
146
        return 0;
147
}
148
 
149
static int isl1208_i2c_get_sr(struct i2c_client *client)
150
{
151
        return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0;
152
}
153
 
154
static int isl1208_i2c_get_atr(struct i2c_client *client)
155
{
156
        int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR);
157
 
158
        if (atr < 0)
159
                return -EIO;
160
 
161
        /* The 6bit value in the ATR register controls the load
162
         * capacitance C_load * in steps of 0.25pF
163
         *
164
         * bit (1<<5) of the ATR register is inverted
165
         *
166
         * C_load(ATR=0x20) =  4.50pF
167
         * C_load(ATR=0x00) = 12.50pF
168
         * C_load(ATR=0x1f) = 20.25pF
169
         *
170
         */
171
 
172
        atr &= 0x3f; /* mask out lsb */
173
        atr ^= 1<<5; /* invert 6th bit */
174
        atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */
175
 
176
        return atr;
177
}
178
 
179
static int isl1208_i2c_get_dtr(struct i2c_client *client)
180
{
181
        int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR);
182
 
183
        if (dtr < 0)
184
                return -EIO;
185
 
186
        /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
187
        dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1);
188
 
189
        return dtr;
190
}
191
 
192
static int isl1208_i2c_get_usr(struct i2c_client *client)
193
{
194
        u8 buf[ISL1208_USR_SECTION_LEN] = { 0, };
195
        int ret;
196
 
197
        ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf,
198
                                   ISL1208_USR_SECTION_LEN);
199
        if (ret < 0)
200
                return ret;
201
 
202
        return (buf[1] << 8) | buf[0];
203
}
204
 
205
static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
206
{
207
        u8 buf[ISL1208_USR_SECTION_LEN];
208
 
209
        buf[0] = usr & 0xff;
210
        buf[1] = (usr >> 8) & 0xff;
211
 
212
        return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf,
213
                                     ISL1208_USR_SECTION_LEN);
214
}
215
 
216
static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
217
{
218
        struct i2c_client *const client = to_i2c_client(dev);
219
        int sr, dtr, atr, usr;
220
 
221
        sr = isl1208_i2c_get_sr(client);
222
        if (sr < 0) {
223
                dev_err(&client->dev, "%s: reading SR failed\n", __func__);
224
                return sr;
225
        }
226
 
227
        seq_printf(seq, "status_reg\t:%s%s%s%s%s%s (0x%.2x)\n",
228
                   (sr & ISL1208_REG_SR_RTCF) ? " RTCF" : "",
229
                   (sr & ISL1208_REG_SR_BAT) ? " BAT" : "",
230
                   (sr & ISL1208_REG_SR_ALM) ? " ALM" : "",
231
                   (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "",
232
                   (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "",
233
                   (sr & ISL1208_REG_SR_ARST) ? " ARST" : "",
234
                   sr);
235
 
236
        seq_printf(seq, "batt_status\t: %s\n",
237
                   (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
238
 
239
        dtr = isl1208_i2c_get_dtr(client);
240
        if (dtr >= 0 -1)
241
                seq_printf(seq, "digital_trim\t: %d ppm\n", dtr);
242
 
243
        atr = isl1208_i2c_get_atr(client);
244
        if (atr >= 0)
245
                seq_printf(seq, "analog_trim\t: %d.%.2d pF\n",
246
                           atr>>2, (atr&0x3)*25);
247
 
248
        usr = isl1208_i2c_get_usr(client);
249
        if (usr >= 0)
250
                seq_printf(seq, "user_data\t: 0x%.4x\n", usr);
251
 
252
        return 0;
253
}
254
 
255
 
256
static int isl1208_i2c_read_time(struct i2c_client *client,
257
                                 struct rtc_time *tm)
258
{
259
        int sr;
260
        u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
261
 
262
        sr = isl1208_i2c_get_sr(client);
263
        if (sr < 0) {
264
                dev_err(&client->dev, "%s: reading SR failed\n", __func__);
265
                return -EIO;
266
        }
267
 
268
        sr = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
269
        if (sr < 0) {
270
                dev_err(&client->dev, "%s: reading RTC section failed\n",
271
                        __func__);
272
                return sr;
273
        }
274
 
275
        tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]);
276
        tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]);
277
        { /* HR field has a more complex interpretation */
278
                const u8 _hr = regs[ISL1208_REG_HR];
279
                if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
280
                        tm->tm_hour = BCD2BIN(_hr & 0x3f);
281
                else { // 12h format
282
                        tm->tm_hour = BCD2BIN(_hr & 0x1f);
283
                        if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
284
                                tm->tm_hour += 12;
285
                }
286
        }
287
 
288
        tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]);
289
        tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
290
        tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100;
291
        tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]);
292
 
293
        return 0;
294
}
295
 
296
static int isl1208_i2c_read_alarm(struct i2c_client *client,
297
                                  struct rtc_wkalrm *alarm)
298
{
299
        struct rtc_time *const tm = &alarm->time;
300
        u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
301
        int sr;
302
 
303
        sr = isl1208_i2c_get_sr(client);
304
        if (sr < 0) {
305
                dev_err(&client->dev, "%s: reading SR failed\n", __func__);
306
                return sr;
307
        }
308
 
309
        sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs,
310
                                  ISL1208_ALARM_SECTION_LEN);
311
        if (sr < 0) {
312
                dev_err(&client->dev, "%s: reading alarm section failed\n",
313
                        __func__);
314
                return sr;
315
        }
316
 
317
        /* MSB of each alarm register is an enable bit */
318
        tm->tm_sec  = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f);
319
        tm->tm_min  = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f);
320
        tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f);
321
        tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f);
322
        tm->tm_mon  = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1;
323
        tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03);
324
 
325
        return 0;
326
}
327
 
328
static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm)
329
{
330
        return isl1208_i2c_read_time(to_i2c_client(dev), tm);
331
}
332
 
333
static int isl1208_i2c_set_time(struct i2c_client *client,
334
                                struct rtc_time const *tm)
335
{
336
        int sr;
337
        u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
338
 
339
        regs[ISL1208_REG_SC] = BIN2BCD(tm->tm_sec);
340
        regs[ISL1208_REG_MN] = BIN2BCD(tm->tm_min);
341
        regs[ISL1208_REG_HR] = BIN2BCD(tm->tm_hour) | ISL1208_REG_HR_MIL;
342
 
343
        regs[ISL1208_REG_DT] = BIN2BCD(tm->tm_mday);
344
        regs[ISL1208_REG_MO] = BIN2BCD(tm->tm_mon + 1);
345
        regs[ISL1208_REG_YR] = BIN2BCD(tm->tm_year - 100);
346
 
347
        regs[ISL1208_REG_DW] = BIN2BCD(tm->tm_wday & 7);
348
 
349
        sr = isl1208_i2c_get_sr(client);
350
        if (sr < 0) {
351
                dev_err(&client->dev, "%s: reading SR failed\n", __func__);
352
                return sr;
353
        }
354
 
355
        /* set WRTC */
356
        sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
357
                                       sr | ISL1208_REG_SR_WRTC);
358
        if (sr < 0) {
359
                dev_err(&client->dev, "%s: writing SR failed\n", __func__);
360
                return sr;
361
        }
362
 
363
        /* write RTC registers */
364
        sr = isl1208_i2c_set_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
365
        if (sr < 0) {
366
                dev_err(&client->dev, "%s: writing RTC section failed\n",
367
                        __func__);
368
                return sr;
369
        }
370
 
371
        /* clear WRTC again */
372
        sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
373
                                       sr & ~ISL1208_REG_SR_WRTC);
374
        if (sr < 0) {
375
                dev_err(&client->dev, "%s: writing SR failed\n", __func__);
376
                return sr;
377
        }
378
 
379
        return 0;
380
}
381
 
382
 
383
static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
384
{
385
        return isl1208_i2c_set_time(to_i2c_client(dev), tm);
386
}
387
 
388
static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
389
{
390
        return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
391
}
392
 
393
static const struct rtc_class_ops isl1208_rtc_ops = {
394
        .proc           = isl1208_rtc_proc,
395
        .read_time      = isl1208_rtc_read_time,
396
        .set_time       = isl1208_rtc_set_time,
397
        .read_alarm     = isl1208_rtc_read_alarm,
398
        //.set_alarm    = isl1208_rtc_set_alarm,
399
};
400
 
401
/* sysfs interface */
402
 
403
static ssize_t isl1208_sysfs_show_atrim(struct device *dev,
404
                                        struct device_attribute *attr,
405
                                        char *buf)
406
{
407
        int atr;
408
 
409
        atr = isl1208_i2c_get_atr(to_i2c_client(dev));
410
        if (atr < 0)
411
                return atr;
412
 
413
        return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25);
414
}
415
static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL);
416
 
417
static ssize_t isl1208_sysfs_show_dtrim(struct device *dev,
418
                                        struct device_attribute *attr,
419
                                        char *buf)
420
{
421
        int dtr;
422
 
423
        dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
424
        if (dtr < 0)
425
                return dtr;
426
 
427
        return sprintf(buf, "%d ppm\n", dtr);
428
}
429
static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
430
 
431
static ssize_t isl1208_sysfs_show_usr(struct device *dev,
432
                                       struct device_attribute *attr,
433
                                       char *buf)
434
{
435
        int usr;
436
 
437
        usr = isl1208_i2c_get_usr(to_i2c_client(dev));
438
        if (usr < 0)
439
                return usr;
440
 
441
        return sprintf(buf, "0x%.4x\n", usr);
442
}
443
 
444
static ssize_t isl1208_sysfs_store_usr(struct device *dev,
445
                                       struct device_attribute *attr,
446
                                       const char *buf, size_t count)
447
{
448
        int usr = -1;
449
 
450
        if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) {
451
                if (sscanf(buf, "%x", &usr) != 1)
452
                        return -EINVAL;
453
        } else {
454
                if (sscanf(buf, "%d", &usr) != 1)
455
                        return -EINVAL;
456
        }
457
 
458
        if (usr < 0 || usr > 0xffff)
459
                return -EINVAL;
460
 
461
        return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
462
}
463
static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
464
                   isl1208_sysfs_store_usr);
465
 
466
static int
467
isl1208_probe(struct i2c_adapter *adapter, int addr, int kind)
468
{
469
        int rc = 0;
470
        struct i2c_client *new_client = NULL;
471
        struct rtc_device *rtc = NULL;
472
 
473
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
474
                rc = -ENODEV;
475
                goto failout;
476
        }
477
 
478
        new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
479
        if (new_client == NULL) {
480
                rc = -ENOMEM;
481
                goto failout;
482
        }
483
 
484
        new_client->addr = addr;
485
        new_client->adapter = adapter;
486
        new_client->driver = &isl1208_driver;
487
        new_client->flags = 0;
488
        strcpy(new_client->name, DRV_NAME);
489
 
490
        if (kind < 0) {
491
                rc = isl1208_i2c_validate_client(new_client);
492
                if (rc < 0)
493
                        goto failout;
494
        }
495
 
496
        rc = i2c_attach_client(new_client);
497
        if (rc < 0)
498
                goto failout;
499
 
500
        dev_info(&new_client->dev,
501
                 "chip found, driver version " DRV_VERSION "\n");
502
 
503
        rtc = rtc_device_register(isl1208_driver.driver.name,
504
                                  &new_client->dev,
505
                                  &isl1208_rtc_ops, THIS_MODULE);
506
 
507
        if (IS_ERR(rtc)) {
508
                rc = PTR_ERR(rtc);
509
                goto failout_detach;
510
        }
511
 
512
        i2c_set_clientdata(new_client, rtc);
513
 
514
        rc = isl1208_i2c_get_sr(new_client);
515
        if (rc < 0) {
516
                dev_err(&new_client->dev, "reading status failed\n");
517
                goto failout_unregister;
518
        }
519
 
520
        if (rc & ISL1208_REG_SR_RTCF)
521
                dev_warn(&new_client->dev, "rtc power failure detected, "
522
                         "please set clock.\n");
523
 
524
        rc = device_create_file(&new_client->dev, &dev_attr_atrim);
525
        if (rc < 0)
526
                goto failout_unregister;
527
        rc = device_create_file(&new_client->dev, &dev_attr_dtrim);
528
        if (rc < 0)
529
                goto failout_atrim;
530
        rc = device_create_file(&new_client->dev, &dev_attr_usr);
531
        if (rc < 0)
532
                goto failout_dtrim;
533
 
534
        return 0;
535
 
536
 failout_dtrim:
537
        device_remove_file(&new_client->dev, &dev_attr_dtrim);
538
 failout_atrim:
539
        device_remove_file(&new_client->dev, &dev_attr_atrim);
540
 failout_unregister:
541
        rtc_device_unregister(rtc);
542
 failout_detach:
543
        i2c_detach_client(new_client);
544
 failout:
545
        kfree(new_client);
546
        return rc;
547
}
548
 
549
static int
550
isl1208_attach_adapter (struct i2c_adapter *adapter)
551
{
552
        return i2c_probe(adapter, &addr_data, isl1208_probe);
553
}
554
 
555
static int
556
isl1208_detach_client(struct i2c_client *client)
557
{
558
        int rc;
559
        struct rtc_device *const rtc = i2c_get_clientdata(client);
560
 
561
        if (rtc)
562
                rtc_device_unregister(rtc); /* do we need to kfree? */
563
 
564
        rc = i2c_detach_client(client);
565
        if (rc)
566
                return rc;
567
 
568
        kfree(client);
569
 
570
        return 0;
571
}
572
 
573
/* module management */
574
 
575
static int __init isl1208_init(void)
576
{
577
        return i2c_add_driver(&isl1208_driver);
578
}
579
 
580
static void __exit isl1208_exit(void)
581
{
582
        i2c_del_driver(&isl1208_driver);
583
}
584
 
585
MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
586
MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
587
MODULE_LICENSE("GPL");
588
MODULE_VERSION(DRV_VERSION);
589
 
590
module_init(isl1208_init);
591
module_exit(isl1208_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.