Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1 201 lines 4.2 kB view raw
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 15MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 16MODULE_DESCRIPTION("TI BQ4802 RTC driver"); 17MODULE_LICENSE("GPL"); 18 19struct 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 29static u8 bq4802_read_io(struct bq4802 *p, int off) 30{ 31 return inb(p->ioport + off); 32} 33 34static void bq4802_write_io(struct bq4802 *p, int off, u8 val) 35{ 36 outb(val, p->ioport + off); 37} 38 39static u8 bq4802_read_mem(struct bq4802 *p, int off) 40{ 41 return readb(p->regs + off); 42} 43 44static void bq4802_write_mem(struct bq4802 *p, int off, u8 val) 45{ 46 writeb(val, p->regs + off); 47} 48 49static int bq4802_read_time(struct device *dev, struct rtc_time *tm) 50{ 51 struct bq4802 *p = dev_get_drvdata(dev); 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 91static int bq4802_set_time(struct device *dev, struct rtc_time *tm) 92{ 93 struct bq4802 *p = dev_get_drvdata(dev); 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 sec = bin2bcd(sec); 109 min = bin2bcd(min); 110 hrs = bin2bcd(hrs); 111 day = bin2bcd(day); 112 mon = bin2bcd(mon); 113 yrs = bin2bcd(yrs); 114 century = bin2bcd(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 136static const struct rtc_class_ops bq4802_ops = { 137 .read_time = bq4802_read_time, 138 .set_time = bq4802_set_time, 139}; 140 141static int bq4802_probe(struct platform_device *pdev) 142{ 143 struct bq4802 *p = devm_kzalloc(&pdev->dev, 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; 157 } 158 if (p->r->flags & IORESOURCE_IO) { 159 p->ioport = 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 = devm_ioremap(&pdev->dev, p->r->start, 164 resource_size(p->r)); 165 if (!p->regs){ 166 err = -ENOMEM; 167 goto out; 168 } 169 p->read = bq4802_read_mem; 170 p->write = bq4802_write_mem; 171 } else { 172 err = -EINVAL; 173 goto out; 174 } 175 176 platform_set_drvdata(pdev, p); 177 178 p->rtc = devm_rtc_device_register(&pdev->dev, "bq4802", 179 &bq4802_ops, THIS_MODULE); 180 if (IS_ERR(p->rtc)) { 181 err = PTR_ERR(p->rtc); 182 goto out; 183 } 184 185 err = 0; 186out: 187 return err; 188 189} 190 191/* work with hotplug and coldplug */ 192MODULE_ALIAS("platform:rtc-bq4802"); 193 194static struct platform_driver bq4802_driver = { 195 .driver = { 196 .name = "rtc-bq4802", 197 }, 198 .probe = bq4802_probe, 199}; 200 201module_platform_driver(bq4802_driver);