brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 472e756 Raw
203 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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);203