cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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);