rtc-bq4802.c (4267B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* rtc-bq4802.c: TI BQ4802 RTC driver. 3 * 4 * Copyright (C) 2008 David S. Miller <davem@davemloft.net> 5 */ 6 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/init.h> 10#include <linux/io.h> 11#include <linux/platform_device.h> 12#include <linux/rtc.h> 13#include <linux/bcd.h> 14#include <linux/slab.h> 15 16MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 17MODULE_DESCRIPTION("TI BQ4802 RTC driver"); 18MODULE_LICENSE("GPL"); 19 20struct bq4802 { 21 void __iomem *regs; 22 unsigned long ioport; 23 struct rtc_device *rtc; 24 spinlock_t lock; 25 struct resource *r; 26 u8 (*read)(struct bq4802 *, int); 27 void (*write)(struct bq4802 *, int, u8); 28}; 29 30static u8 bq4802_read_io(struct bq4802 *p, int off) 31{ 32 return inb(p->ioport + off); 33} 34 35static void bq4802_write_io(struct bq4802 *p, int off, u8 val) 36{ 37 outb(val, p->ioport + off); 38} 39 40static u8 bq4802_read_mem(struct bq4802 *p, int off) 41{ 42 return readb(p->regs + off); 43} 44 45static void bq4802_write_mem(struct bq4802 *p, int off, u8 val) 46{ 47 writeb(val, p->regs + off); 48} 49 50static int bq4802_read_time(struct device *dev, struct rtc_time *tm) 51{ 52 struct bq4802 *p = dev_get_drvdata(dev); 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 92static int bq4802_set_time(struct device *dev, struct rtc_time *tm) 93{ 94 struct bq4802 *p = dev_get_drvdata(dev); 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 137static const struct rtc_class_ops bq4802_ops = { 138 .read_time = bq4802_read_time, 139 .set_time = bq4802_set_time, 140}; 141 142static int bq4802_probe(struct platform_device *pdev) 143{ 144 struct bq4802 *p = devm_kzalloc(&pdev->dev, 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; 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 = devm_ioremap(&pdev->dev, p->r->start, 165 resource_size(p->r)); 166 if (!p->regs){ 167 err = -ENOMEM; 168 goto out; 169 } 170 p->read = bq4802_read_mem; 171 p->write = bq4802_write_mem; 172 } else { 173 err = -EINVAL; 174 goto out; 175 } 176 177 platform_set_drvdata(pdev, p); 178 179 p->rtc = devm_rtc_device_register(&pdev->dev, "bq4802", 180 &bq4802_ops, THIS_MODULE); 181 if (IS_ERR(p->rtc)) { 182 err = PTR_ERR(p->rtc); 183 goto out; 184 } 185 186 err = 0; 187out: 188 return err; 189 190} 191 192/* work with hotplug and coldplug */ 193MODULE_ALIAS("platform:rtc-bq4802"); 194 195static struct platform_driver bq4802_driver = { 196 .driver = { 197 .name = "rtc-bq4802", 198 }, 199 .probe = bq4802_probe, 200}; 201 202module_platform_driver(bq4802_driver);