1 /* rtc-bq4802.c: TI BQ4802 RTC driver. 2 * 3 * Copyright (C) 2008 David S. Miller <davem@davemloft.net> 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 <davem@davemloft.net>"); 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; 23 spinlock_t lock; 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 { 51 struct platform_device *pdev = to_platform_device(dev); 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 198 rtc_device_unregister(p->rtc); 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 static int __init bq4802_init(void) 222 { 223 return platform_driver_register(&bq4802_driver); 224 } 225 226 static void __exit bq4802_exit(void) 227 { 228 platform_driver_unregister(&bq4802_driver); 229 } 230 231 module_init(bq4802_init); 232 module_exit(bq4802_exit); 233