1 /* rtc-bq4802.c: TI BQ4802 RTC driver.
3 * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/init.h>
10 #include <linux/platform_device.h>
11 #include <linux/rtc.h>
12 #include <linux/bcd.h>
13 #include <linux/slab.h>
15 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
16 MODULE_DESCRIPTION("TI BQ4802 RTC driver");
17 MODULE_LICENSE("GPL");
22 struct rtc_device
*rtc
;
25 u8 (*read
)(struct bq4802
*, int);
26 void (*write
)(struct bq4802
*, int, u8
);
29 static u8
bq4802_read_io(struct bq4802
*p
, int off
)
31 return inb(p
->ioport
+ off
);
34 static void bq4802_write_io(struct bq4802
*p
, int off
, u8 val
)
36 outb(val
, p
->ioport
+ off
);
39 static u8
bq4802_read_mem(struct bq4802
*p
, int off
)
41 return readb(p
->regs
+ off
);
44 static void bq4802_write_mem(struct bq4802
*p
, int off
, u8 val
)
46 writeb(val
, p
->regs
+ off
);
49 static int bq4802_read_time(struct device
*dev
, struct rtc_time
*tm
)
51 struct platform_device
*pdev
= to_platform_device(dev
);
52 struct bq4802
*p
= platform_get_drvdata(pdev
);
57 spin_lock_irqsave(&p
->lock
, flags
);
59 val
= p
->read(p
, 0x0e);
60 p
->write(p
, 0xe, val
| 0x08);
62 tm
->tm_sec
= p
->read(p
, 0x00);
63 tm
->tm_min
= p
->read(p
, 0x02);
64 tm
->tm_hour
= p
->read(p
, 0x04);
65 tm
->tm_mday
= p
->read(p
, 0x06);
66 tm
->tm_mon
= p
->read(p
, 0x09);
67 tm
->tm_year
= p
->read(p
, 0x0a);
68 tm
->tm_wday
= p
->read(p
, 0x08);
69 century
= p
->read(p
, 0x0f);
71 p
->write(p
, 0x0e, val
);
73 spin_unlock_irqrestore(&p
->lock
, flags
);
75 tm
->tm_sec
= bcd2bin(tm
->tm_sec
);
76 tm
->tm_min
= bcd2bin(tm
->tm_min
);
77 tm
->tm_hour
= bcd2bin(tm
->tm_hour
);
78 tm
->tm_mday
= bcd2bin(tm
->tm_mday
);
79 tm
->tm_mon
= bcd2bin(tm
->tm_mon
);
80 tm
->tm_year
= bcd2bin(tm
->tm_year
);
81 tm
->tm_wday
= bcd2bin(tm
->tm_wday
);
82 century
= bcd2bin(century
);
84 tm
->tm_year
+= (century
* 100);
92 static int bq4802_set_time(struct device
*dev
, struct rtc_time
*tm
)
94 struct platform_device
*pdev
= to_platform_device(dev
);
95 struct bq4802
*p
= platform_get_drvdata(pdev
);
96 u8 sec
, min
, hrs
, day
, mon
, yrs
, century
, val
;
100 year
= tm
->tm_year
+ 1900;
101 century
= year
/ 100;
104 mon
= tm
->tm_mon
+ 1; /* tm_mon starts at zero */
116 century
= bin2bcd(century
);
118 spin_lock_irqsave(&p
->lock
, flags
);
120 val
= p
->read(p
, 0x0e);
121 p
->write(p
, 0x0e, val
| 0x08);
123 p
->write(p
, 0x00, sec
);
124 p
->write(p
, 0x02, min
);
125 p
->write(p
, 0x04, hrs
);
126 p
->write(p
, 0x06, day
);
127 p
->write(p
, 0x09, mon
);
128 p
->write(p
, 0x0a, yrs
);
129 p
->write(p
, 0x0f, century
);
131 p
->write(p
, 0x0e, val
);
133 spin_unlock_irqrestore(&p
->lock
, flags
);
138 static const struct rtc_class_ops bq4802_ops
= {
139 .read_time
= bq4802_read_time
,
140 .set_time
= bq4802_set_time
,
143 static int bq4802_probe(struct platform_device
*pdev
)
145 struct bq4802
*p
= kzalloc(sizeof(*p
), GFP_KERNEL
);
151 spin_lock_init(&p
->lock
);
153 p
->r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
155 p
->r
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
160 if (p
->r
->flags
& IORESOURCE_IO
) {
161 p
->ioport
= p
->r
->start
;
162 p
->read
= bq4802_read_io
;
163 p
->write
= bq4802_write_io
;
164 } else if (p
->r
->flags
& IORESOURCE_MEM
) {
165 p
->regs
= ioremap(p
->r
->start
, resource_size(p
->r
));
166 p
->read
= bq4802_read_mem
;
167 p
->write
= bq4802_write_mem
;
173 platform_set_drvdata(pdev
, p
);
175 p
->rtc
= rtc_device_register("bq4802", &pdev
->dev
,
176 &bq4802_ops
, THIS_MODULE
);
177 if (IS_ERR(p
->rtc
)) {
178 err
= PTR_ERR(p
->rtc
);
187 if (p
->r
->flags
& IORESOURCE_MEM
)
194 static int bq4802_remove(struct platform_device
*pdev
)
196 struct bq4802
*p
= platform_get_drvdata(pdev
);
198 rtc_device_unregister(p
->rtc
);
199 if (p
->r
->flags
& IORESOURCE_MEM
)
202 platform_set_drvdata(pdev
, NULL
);
209 /* work with hotplug and coldplug */
210 MODULE_ALIAS("platform:rtc-bq4802");
212 static struct platform_driver bq4802_driver
= {
214 .name
= "rtc-bq4802",
215 .owner
= THIS_MODULE
,
217 .probe
= bq4802_probe
,
218 .remove
= bq4802_remove
,
221 module_platform_driver(bq4802_driver
);