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