Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rtc-bq4802.c
Go to the documentation of this file.
1 /* rtc-bq4802.c: TI BQ4802 RTC driver.
2  *
3  * Copyright (C) 2008 David S. Miller <[email protected]>
4  */
5 
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/init.h>
9 #include <linux/io.h>
10 #include <linux/platform_device.h>
11 #include <linux/rtc.h>
12 #include <linux/bcd.h>
13 #include <linux/slab.h>
14 
15 MODULE_AUTHOR("David S. Miller <[email protected]>");
16 MODULE_DESCRIPTION("TI BQ4802 RTC driver");
17 MODULE_LICENSE("GPL");
18 
19 struct bq4802 {
20  void __iomem *regs;
21  unsigned long ioport;
22  struct rtc_device *rtc;
24  struct resource *r;
25  u8 (*read)(struct bq4802 *, int);
26  void (*write)(struct bq4802 *, int, u8);
27 };
28 
29 static u8 bq4802_read_io(struct bq4802 *p, int off)
30 {
31  return inb(p->ioport + off);
32 }
33 
34 static void bq4802_write_io(struct bq4802 *p, int off, u8 val)
35 {
36  outb(val, p->ioport + off);
37 }
38 
39 static u8 bq4802_read_mem(struct bq4802 *p, int off)
40 {
41  return readb(p->regs + off);
42 }
43 
44 static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
45 {
46  writeb(val, p->regs + off);
47 }
48 
49 static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
50 {
52  struct bq4802 *p = platform_get_drvdata(pdev);
53  unsigned long flags;
54  unsigned int century;
55  u8 val;
56 
57  spin_lock_irqsave(&p->lock, flags);
58 
59  val = p->read(p, 0x0e);
60  p->write(p, 0xe, val | 0x08);
61 
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);
70 
71  p->write(p, 0x0e, val);
72 
73  spin_unlock_irqrestore(&p->lock, flags);
74 
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);
83 
84  tm->tm_year += (century * 100);
85  tm->tm_year -= 1900;
86 
87  tm->tm_mon--;
88 
89  return 0;
90 }
91 
92 static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
93 {
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;
97  unsigned long flags;
98  unsigned int year;
99 
100  year = tm->tm_year + 1900;
101  century = year / 100;
102  yrs = year % 100;
103 
104  mon = tm->tm_mon + 1; /* tm_mon starts at zero */
105  day = tm->tm_mday;
106  hrs = tm->tm_hour;
107  min = tm->tm_min;
108  sec = tm->tm_sec;
109 
110  sec = bin2bcd(sec);
111  min = bin2bcd(min);
112  hrs = bin2bcd(hrs);
113  day = bin2bcd(day);
114  mon = bin2bcd(mon);
115  yrs = bin2bcd(yrs);
116  century = bin2bcd(century);
117 
118  spin_lock_irqsave(&p->lock, flags);
119 
120  val = p->read(p, 0x0e);
121  p->write(p, 0x0e, val | 0x08);
122 
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);
130 
131  p->write(p, 0x0e, val);
132 
133  spin_unlock_irqrestore(&p->lock, flags);
134 
135  return 0;
136 }
137 
138 static const struct rtc_class_ops bq4802_ops = {
139  .read_time = bq4802_read_time,
140  .set_time = bq4802_set_time,
141 };
142 
143 static int __devinit bq4802_probe(struct platform_device *pdev)
144 {
145  struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
146  int err = -ENOMEM;
147 
148  if (!p)
149  goto out;
150 
151  spin_lock_init(&p->lock);
152 
153  p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
154  if (!p->r) {
155  p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
156  err = -EINVAL;
157  if (!p->r)
158  goto out_free;
159  }
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;
168  } else {
169  err = -EINVAL;
170  goto out_free;
171  }
172 
173  platform_set_drvdata(pdev, p);
174 
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);
179  goto out_iounmap;
180  }
181 
182  err = 0;
183 out:
184  return err;
185 
186 out_iounmap:
187  if (p->r->flags & IORESOURCE_MEM)
188  iounmap(p->regs);
189 out_free:
190  kfree(p);
191  goto out;
192 }
193 
194 static int __devexit bq4802_remove(struct platform_device *pdev)
195 {
196  struct bq4802 *p = platform_get_drvdata(pdev);
197 
199  if (p->r->flags & IORESOURCE_MEM)
200  iounmap(p->regs);
201 
202  platform_set_drvdata(pdev, NULL);
203 
204  kfree(p);
205 
206  return 0;
207 }
208 
209 /* work with hotplug and coldplug */
210 MODULE_ALIAS("platform:rtc-bq4802");
211 
212 static struct platform_driver bq4802_driver = {
213  .driver = {
214  .name = "rtc-bq4802",
215  .owner = THIS_MODULE,
216  },
217  .probe = bq4802_probe,
218  .remove = __devexit_p(bq4802_remove),
219 };
220 
221 module_platform_driver(bq4802_driver);