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 14 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 15 MODULE_DESCRIPTION("TI BQ4802 RTC driver"); 16 MODULE_LICENSE("GPL"); 17 18 struct bq4802 { 19 void __iomem *regs; 20 unsigned long ioport; 21 struct rtc_device *rtc; 22 spinlock_t lock; 23 struct resource *r; 24 u8 (*read)(struct bq4802 *, int); 25 void (*write)(struct bq4802 *, int, u8); 26 }; 27 28 static u8 bq4802_read_io(struct bq4802 *p, int off) 29 { 30 return inb(p->ioport + off); 31 } 32 33 static void bq4802_write_io(struct bq4802 *p, int off, u8 val) 34 { 35 outb(val, p->ioport + off); 36 } 37 38 static u8 bq4802_read_mem(struct bq4802 *p, int off) 39 { 40 return readb(p->regs + off); 41 } 42 43 static void bq4802_write_mem(struct bq4802 *p, int off, u8 val) 44 { 45 writeb(val, p->regs + off); 46 } 47 48 static int bq4802_read_time(struct device *dev, struct rtc_time *tm) 49 { 50 struct platform_device *pdev = to_platform_device(dev); 51 struct bq4802 *p = platform_get_drvdata(pdev); 52 unsigned long flags; 53 unsigned int century; 54 u8 val; 55 56 spin_lock_irqsave(&p->lock, flags); 57 58 val = p->read(p, 0x0e); 59 p->write(p, 0xe, val | 0x08); 60 61 tm->tm_sec = p->read(p, 0x00); 62 tm->tm_min = p->read(p, 0x02); 63 tm->tm_hour = p->read(p, 0x04); 64 tm->tm_mday = p->read(p, 0x06); 65 tm->tm_mon = p->read(p, 0x09); 66 tm->tm_year = p->read(p, 0x0a); 67 tm->tm_wday = p->read(p, 0x08); 68 century = p->read(p, 0x0f); 69 70 p->write(p, 0x0e, val); 71 72 spin_unlock_irqrestore(&p->lock, flags); 73 74 tm->tm_sec = bcd2bin(tm->tm_sec); 75 tm->tm_min = bcd2bin(tm->tm_min); 76 tm->tm_hour = bcd2bin(tm->tm_hour); 77 tm->tm_mday = bcd2bin(tm->tm_mday); 78 tm->tm_mon = bcd2bin(tm->tm_mon); 79 tm->tm_year = bcd2bin(tm->tm_year); 80 tm->tm_wday = bcd2bin(tm->tm_wday); 81 century = bcd2bin(century); 82 83 tm->tm_year += (century * 100); 84 tm->tm_year -= 1900; 85 86 tm->tm_mon--; 87 88 return 0; 89 } 90 91 static int bq4802_set_time(struct device *dev, struct rtc_time *tm) 92 { 93 struct platform_device *pdev = to_platform_device(dev); 94 struct bq4802 *p = platform_get_drvdata(pdev); 95 u8 sec, min, hrs, day, mon, yrs, century, val; 96 unsigned long flags; 97 unsigned int year; 98 99 year = tm->tm_year + 1900; 100 century = year / 100; 101 yrs = year % 100; 102 103 mon = tm->tm_mon + 1; /* tm_mon starts at zero */ 104 day = tm->tm_mday; 105 hrs = tm->tm_hour; 106 min = tm->tm_min; 107 sec = tm->tm_sec; 108 109 sec = bin2bcd(sec); 110 min = bin2bcd(min); 111 hrs = bin2bcd(hrs); 112 day = bin2bcd(day); 113 mon = bin2bcd(mon); 114 yrs = bin2bcd(yrs); 115 century = bin2bcd(century); 116 117 spin_lock_irqsave(&p->lock, flags); 118 119 val = p->read(p, 0x0e); 120 p->write(p, 0x0e, val | 0x08); 121 122 p->write(p, 0x00, sec); 123 p->write(p, 0x02, min); 124 p->write(p, 0x04, hrs); 125 p->write(p, 0x06, day); 126 p->write(p, 0x09, mon); 127 p->write(p, 0x0a, yrs); 128 p->write(p, 0x0f, century); 129 130 p->write(p, 0x0e, val); 131 132 spin_unlock_irqrestore(&p->lock, flags); 133 134 return 0; 135 } 136 137 static const struct rtc_class_ops bq4802_ops = { 138 .read_time = bq4802_read_time, 139 .set_time = bq4802_set_time, 140 }; 141 142 static int __devinit bq4802_probe(struct platform_device *pdev) 143 { 144 struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL); 145 int err = -ENOMEM; 146 147 if (!p) 148 goto out; 149 150 spin_lock_init(&p->lock); 151 152 p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 153 if (!p->r) { 154 p->r = platform_get_resource(pdev, IORESOURCE_IO, 0); 155 err = -EINVAL; 156 if (!p->r) 157 goto out_free; 158 } 159 if (p->r->flags & IORESOURCE_IO) { 160 p->ioport = p->r->start; 161 p->read = bq4802_read_io; 162 p->write = bq4802_write_io; 163 } else if (p->r->flags & IORESOURCE_MEM) { 164 p->regs = ioremap(p->r->start, resource_size(p->r)); 165 p->read = bq4802_read_mem; 166 p->write = bq4802_write_mem; 167 } else { 168 err = -EINVAL; 169 goto out_free; 170 } 171 172 platform_set_drvdata(pdev, p); 173 174 p->rtc = rtc_device_register("bq4802", &pdev->dev, 175 &bq4802_ops, THIS_MODULE); 176 if (IS_ERR(p->rtc)) { 177 err = PTR_ERR(p->rtc); 178 goto out_iounmap; 179 } 180 181 err = 0; 182 out: 183 return err; 184 185 out_iounmap: 186 if (p->r->flags & IORESOURCE_MEM) 187 iounmap(p->regs); 188 out_free: 189 kfree(p); 190 goto out; 191 } 192 193 static int __devexit bq4802_remove(struct platform_device *pdev) 194 { 195 struct bq4802 *p = platform_get_drvdata(pdev); 196 197 rtc_device_unregister(p->rtc); 198 if (p->r->flags & IORESOURCE_MEM) 199 iounmap(p->regs); 200 201 platform_set_drvdata(pdev, NULL); 202 203 kfree(p); 204 205 return 0; 206 } 207 208 /* work with hotplug and coldplug */ 209 MODULE_ALIAS("platform:rtc-bq4802"); 210 211 static struct platform_driver bq4802_driver = { 212 .driver = { 213 .name = "rtc-bq4802", 214 .owner = THIS_MODULE, 215 }, 216 .probe = bq4802_probe, 217 .remove = __devexit_p(bq4802_remove), 218 }; 219 220 static int __init bq4802_init(void) 221 { 222 return platform_driver_register(&bq4802_driver); 223 } 224 225 static void __exit bq4802_exit(void) 226 { 227 platform_driver_unregister(&bq4802_driver); 228 } 229 230 module_init(bq4802_init); 231 module_exit(bq4802_exit); 232