2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-15 08:44:14 +08:00

RTC for 4.14

Subsystem:
  - Remove .open() and .release() RTC ops
  - constify i2c_device_id
 
 New driver:
  - Realtek RTD1295
  - Android emulator (goldfish) RTC
 
 Drivers:
  - ds1307: Beginning of a huge cleanup
  - s35390a: handle invalid RTC time
  - sun6i: external oscillator gate support
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEXx9Viay1+e7J/aM4AyWl4gNJNJIFAlm5YTcACgkQAyWl4gNJ
 NJKetg//Xz4zK3O1uhfz1/yWOSqbBwYxUvHzSDFuD3FtAskFPPFACgJENkj98DMF
 w6nCqq/TXOY+BpqPTebzc68vvHGCvZ/AEKPzvCV1KciQ+ACMFGxH8xHCLox9AdyL
 VtcWftPPwu3W6oNN1azV++XgVtComzfEi4pTcTXdw9EDA5yBK/Xyg3xWZ1QV/Xs5
 /DFCcY69nhaJxmD/To0csmI1KbMbiprvN0vJHtF589Y4KhBfnlZnq3bAx2Coo1kv
 PpPy0e0kLzzlWMtMsiM6I3w5iwuf5o1Vajcg5ylAK0Wjvfgh7DqYX0ZQySw/5eZT
 f1OCqP0GVSugmJ8SFMVxYbXPGgpUETtT6ztB9fsAYdUye3I/xfqmip3A7vcFlrAb
 /R1gTZOyx/uwv3qVRsx0LJVxJQJ7vq/3dJYFiQo80AbPyY+GQT3xPr3z33DcJYJt
 2CL0pd6NfEzgesuVCnpZxF+wNJ+449Jzmxge5klqH1rYQ/IjOXS0qAg5pQRUaRjC
 CGNkjBWT82HN1Y8G++4FpdmHLUjkO07QyAAZiYvHNXX3aMcyl8Az/2kcrl+yq7tl
 03CxveLD8kP1bVsRMEIbx24l4lB93U5HyFTeli9xjBMbxDrBK2NZXCD7g/yI/sbs
 ryUe5W33Xgxm0DJ9CXts0qOf/ommiBoogYk+oxe+AGWdLR1weRo=
 =Xkx1
 -----END PGP SIGNATURE-----

Merge tag 'rtc-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "Subsystem:
   - remove .open() and .release() RTC ops
   - constify i2c_device_id

  New driver:
   - Realtek RTD1295
   - Android emulator (goldfish) RTC

  Drivers:
   - ds1307: Beginning of a huge cleanup
   - s35390a: handle invalid RTC time
   - sun6i: external oscillator gate support"

* tag 'rtc-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (40 commits)
  rtc: ds1307: use octal permissions
  rtc: ds1307: fix braces
  rtc: ds1307: fix alignments and blank lines
  rtc: ds1307: use BIT
  rtc: ds1307: use u32
  rtc: ds1307: use sizeof
  rtc: ds1307: remove regs member
  rtc: Add Realtek RTD1295
  dt-bindings: rtc: Add Realtek RTD1295
  rtc: sun6i: Add support for the external oscillator gate
  rtc: goldfish: Add RTC driver for Android emulator
  dt-bindings: Add device tree binding for Goldfish RTC driver
  rtc: ds1307: add basic support for ds1341 chip
  rtc: ds1307: remove member nvram_offset from struct ds1307
  rtc: ds1307: factor out offset to struct chip_desc
  rtc: ds1307: factor out rtc_ops to struct chip_desc
  rtc: ds1307: factor out irq_handler to struct chip_desc
  rtc: ds1307: improve irq setup
  rtc: ds1307: constify struct chip_desc variables
  rtc: ds1307: improve trickle charger initialization
  ...
This commit is contained in:
Linus Torvalds 2017-09-13 10:56:00 -07:00
commit 561a8eb3e1
26 changed files with 955 additions and 487 deletions

View File

@ -20,13 +20,12 @@ List of legacy properties and respective binding document
1. "enable-sdio-wakeup" Documentation/devicetree/bindings/mmc/mmc.txt
2. "gpio-key,wakeup" Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
3. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt
4. "isil,irq2-can-wakeup-machine" Documentation/devicetree/bindings/rtc/isil,isl12057.txt
5. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
4. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
Documentation/devicetree/bindings/mfd/tc3589x.txt
Documentation/devicetree/bindings/input/ads7846.txt
6. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
7. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt
8. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
5. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
6. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt
7. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
Examples
--------

View File

@ -0,0 +1,17 @@
Android Goldfish RTC
Android Goldfish RTC device used by Android emulator.
Required properties:
- compatible : should contain "google,goldfish-rtc"
- reg : <registers mapping>
- interrupts : <interrupt mapping>
Example:
goldfish_timer@9020000 {
compatible = "google,goldfish-rtc";
reg = <0x9020000 0x1000>;
interrupts = <0x3>;
};

View File

@ -24,7 +24,6 @@ Optional properties:
- "wakeup-source": mark the chip as a wakeup source, independently of
the availability of an IRQ line connected to the SoC.
(Legacy property supported: "isil,irq2-can-wakeup-machine")
- "interrupt-parent", "interrupts": for passing the interrupt line
of the SoC connected to IRQ#2 of the RTC chip.

View File

@ -0,0 +1,16 @@
Realtek RTD129x Real-Time Clock
===============================
Required properties:
- compatible : Should be "realtek,rtd1295-rtc"
- reg : Specifies the physical base address and size
- clocks : Specifies the clock gate
Example:
rtc@9801b600 {
compatible = "realtek,rtd1295-clk";
reg = <0x9801b600 0x100>;
clocks = <&clkc RTD1295_CLK_EN_MISC_RTC>;
};

View File

@ -10,7 +10,7 @@ Required properties:
Required properties for new device trees
- clocks : phandle to the 32kHz external oscillator
- clock-output-names : name of the LOSC clock created
- clock-output-names : names of the LOSC and its external output clocks created
- #clock-cells : must be equals to 1. The RTC provides two clocks: the
LOSC and its external output, with index 0 and 1
respectively.
@ -21,7 +21,7 @@ rtc: rtc@01f00000 {
compatible = "allwinner,sun6i-a31-rtc";
reg = <0x01f00000 0x54>;
interrupts = <0 40 4>, <0 41 4>;
clock-output-names = "osc32k";
clock-output-names = "osc32k", "osc32k-out";
clocks = <&ext_osc32k>;
#clock-cells = <1>;
};

View File

@ -855,6 +855,12 @@ S: Supported
F: drivers/android/
F: drivers/staging/android/
ANDROID GOLDFISH RTC DRIVER
M: Miodrag Dinic <miodrag.dinic@imgtec.com>
S: Supported
F: Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt
F: drivers/rtc/rtc-goldfish.c
ANDROID ION DRIVER
M: Laura Abbott <labbott@redhat.com>
M: Sumit Semwal <sumit.semwal@linaro.org>

View File

@ -227,14 +227,14 @@ config RTC_DRV_AS3722
will be called rtc-as3722.
config RTC_DRV_DS1307
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025, ISL12057"
tristate "Dallas/Maxim DS1307/37/38/39/40/41, ST M41T00, EPSON RX-8025, ISL12057"
help
If you say yes here you get support for various compatible RTC
chips (often with battery backup) connected with I2C. This driver
should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
EPSON RX-8025, Intersil ISL12057 and probably other chips. In some
cases the RTC must already have been initialized (by manufacturing or
a bootloader).
should handle DS1307, DS1337, DS1338, DS1339, DS1340, DS1341,
ST M41T00, EPSON RX-8025, Intersil ISL12057 and probably other chips.
In some cases the RTC must already have been initialized (by
manufacturing or a bootloader).
The first seven registers on these chips hold an RTC, and other
registers may add features such as NVRAM, a trickle charger for
@ -371,11 +371,11 @@ config RTC_DRV_MAX77686
will be called rtc-max77686.
config RTC_DRV_RK808
tristate "Rockchip RK808/RK818 RTC"
tristate "Rockchip RK805/RK808/RK818 RTC"
depends on MFD_RK808
help
If you say yes here you will get support for the
RTC of RK808 and RK818 PMIC.
RTC of RK805, RK808 and RK818 PMIC.
This driver can also be built as a module. If so, the module
will be called rk808-rtc.
@ -1765,6 +1765,14 @@ config RTC_DRV_CPCAP
Say y here for CPCAP rtc found on some Motorola phones
and tablets such as Droid 4.
config RTC_DRV_RTD119X
bool "Realtek RTD129x RTC"
depends on ARCH_REALTEK || COMPILE_TEST
default ARCH_REALTEK
help
If you say yes here, you get support for the RTD1295 SoC
Real Time Clock.
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME
@ -1780,5 +1788,13 @@ config RTC_DRV_HID_SENSOR_TIME
If this driver is compiled as a module, it will be named
rtc-hid-sensor-time.
config RTC_DRV_GOLDFISH
tristate "Goldfish Real Time Clock"
depends on MIPS && (GOLDFISH || COMPILE_TEST)
help
Say yes to enable RTC driver for the Goldfish based virtual platform.
Goldfish is a code name for the virtual platform developed by Google
for Android emulation.
endif # RTC_CLASS

View File

@ -131,6 +131,7 @@ obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RTD119X) += rtc-rtd119x.o
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
@ -170,3 +171,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o
obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o

View File

@ -24,28 +24,19 @@ static dev_t rtc_devt;
static int rtc_dev_open(struct inode *inode, struct file *file)
{
int err;
struct rtc_device *rtc = container_of(inode->i_cdev,
struct rtc_device, char_dev);
const struct rtc_class_ops *ops = rtc->ops;
if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
return -EBUSY;
file->private_data = rtc;
err = ops->open ? ops->open(rtc->dev.parent) : 0;
if (err == 0) {
spin_lock_irq(&rtc->irq_lock);
rtc->irq_data = 0;
spin_unlock_irq(&rtc->irq_lock);
spin_lock_irq(&rtc->irq_lock);
rtc->irq_data = 0;
spin_unlock_irq(&rtc->irq_lock);
return 0;
}
/* something has gone wrong */
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
return err;
return 0;
}
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
@ -438,9 +429,6 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
rtc_update_irq_enable(rtc, 0);
rtc_irq_set_state(rtc, NULL, 0);
if (rtc->ops->release)
rtc->ops->release(rtc->dev.parent);
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -190,7 +190,7 @@ static int ds1672_probe(struct i2c_client *client,
return 0;
}
static struct i2c_device_id ds1672_id[] = {
static const struct i2c_device_id ds1672_id[] = {
{ "ds1672", 0 },
{ }
};

View File

@ -132,7 +132,7 @@ static int em3027_probe(struct i2c_client *client,
return 0;
}
static struct i2c_device_id em3027_id[] = {
static const struct i2c_device_id em3027_id[] = {
{ "em3027", 0 },
{ }
};

237
drivers/rtc/rtc-goldfish.c Normal file
View File

@ -0,0 +1,237 @@
/* drivers/rtc/rtc-goldfish.c
*
* Copyright (C) 2007 Google, Inc.
* Copyright (C) 2017 Imagination Technologies Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/io.h>
#define TIMER_TIME_LOW 0x00 /* get low bits of current time */
/* and update TIMER_TIME_HIGH */
#define TIMER_TIME_HIGH 0x04 /* get high bits of time at last */
/* TIMER_TIME_LOW read */
#define TIMER_ALARM_LOW 0x08 /* set low bits of alarm and */
/* activate it */
#define TIMER_ALARM_HIGH 0x0c /* set high bits of next alarm */
#define TIMER_IRQ_ENABLED 0x10
#define TIMER_CLEAR_ALARM 0x14
#define TIMER_ALARM_STATUS 0x18
#define TIMER_CLEAR_INTERRUPT 0x1c
struct goldfish_rtc {
void __iomem *base;
int irq;
struct rtc_device *rtc;
};
static int goldfish_rtc_read_alarm(struct device *dev,
struct rtc_wkalrm *alrm)
{
u64 rtc_alarm;
u64 rtc_alarm_low;
u64 rtc_alarm_high;
void __iomem *base;
struct goldfish_rtc *rtcdrv;
rtcdrv = dev_get_drvdata(dev);
base = rtcdrv->base;
rtc_alarm_low = readl(base + TIMER_ALARM_LOW);
rtc_alarm_high = readl(base + TIMER_ALARM_HIGH);
rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low;
do_div(rtc_alarm, NSEC_PER_SEC);
memset(alrm, 0, sizeof(struct rtc_wkalrm));
rtc_time_to_tm(rtc_alarm, &alrm->time);
if (readl(base + TIMER_ALARM_STATUS))
alrm->enabled = 1;
else
alrm->enabled = 0;
return 0;
}
static int goldfish_rtc_set_alarm(struct device *dev,
struct rtc_wkalrm *alrm)
{
struct goldfish_rtc *rtcdrv;
unsigned long rtc_alarm;
u64 rtc_alarm64;
u64 rtc_status_reg;
void __iomem *base;
int ret = 0;
rtcdrv = dev_get_drvdata(dev);
base = rtcdrv->base;
if (alrm->enabled) {
ret = rtc_tm_to_time(&alrm->time, &rtc_alarm);
if (ret != 0)
return ret;
rtc_alarm64 = rtc_alarm * NSEC_PER_SEC;
writel((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH);
writel(rtc_alarm64, base + TIMER_ALARM_LOW);
} else {
/*
* if this function was called with enabled=0
* then it could mean that the application is
* trying to cancel an ongoing alarm
*/
rtc_status_reg = readl(base + TIMER_ALARM_STATUS);
if (rtc_status_reg)
writel(1, base + TIMER_CLEAR_ALARM);
}
return ret;
}
static int goldfish_rtc_alarm_irq_enable(struct device *dev,
unsigned int enabled)
{
void __iomem *base;
struct goldfish_rtc *rtcdrv;
rtcdrv = dev_get_drvdata(dev);
base = rtcdrv->base;
if (enabled)
writel(1, base + TIMER_IRQ_ENABLED);
else
writel(0, base + TIMER_IRQ_ENABLED);
return 0;
}
static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id)
{
struct goldfish_rtc *rtcdrv = dev_id;
void __iomem *base = rtcdrv->base;
writel(1, base + TIMER_CLEAR_INTERRUPT);
rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct goldfish_rtc *rtcdrv;
void __iomem *base;
u64 time_high;
u64 time_low;
u64 time;
rtcdrv = dev_get_drvdata(dev);
base = rtcdrv->base;
time_low = readl(base + TIMER_TIME_LOW);
time_high = readl(base + TIMER_TIME_HIGH);
time = (time_high << 32) | time_low;
do_div(time, NSEC_PER_SEC);
rtc_time_to_tm(time, tm);
return 0;
}
static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct goldfish_rtc *rtcdrv;
void __iomem *base;
unsigned long now;
u64 now64;
int ret;
rtcdrv = dev_get_drvdata(dev);
base = rtcdrv->base;
ret = rtc_tm_to_time(tm, &now);
if (ret == 0) {
now64 = now * NSEC_PER_SEC;
writel((now64 >> 32), base + TIMER_TIME_HIGH);
writel(now64, base + TIMER_TIME_LOW);
}
return ret;
}
static const struct rtc_class_ops goldfish_rtc_ops = {
.read_time = goldfish_rtc_read_time,
.set_time = goldfish_rtc_set_time,
.read_alarm = goldfish_rtc_read_alarm,
.set_alarm = goldfish_rtc_set_alarm,
.alarm_irq_enable = goldfish_rtc_alarm_irq_enable
};
static int goldfish_rtc_probe(struct platform_device *pdev)
{
struct goldfish_rtc *rtcdrv;
struct resource *r;
int err;
rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL);
if (!rtcdrv)
return -ENOMEM;
platform_set_drvdata(pdev, rtcdrv);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
rtcdrv->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(rtcdrv->base))
return -ENODEV;
rtcdrv->irq = platform_get_irq(pdev, 0);
if (rtcdrv->irq < 0)
return -ENODEV;
rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&goldfish_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtcdrv->rtc))
return PTR_ERR(rtcdrv->rtc);
err = devm_request_irq(&pdev->dev, rtcdrv->irq,
goldfish_rtc_interrupt,
0, pdev->name, rtcdrv);
if (err)
return err;
return 0;
}
static const struct of_device_id goldfish_rtc_of_match[] = {
{ .compatible = "google,goldfish-rtc", },
{},
};
MODULE_DEVICE_TABLE(of, goldfish_rtc_of_match);
static struct platform_driver goldfish_rtc = {
.probe = goldfish_rtc_probe,
.driver = {
.name = "goldfish_rtc",
.of_match_table = goldfish_rtc_of_match,
}
};
module_platform_driver(goldfish_rtc);

View File

@ -440,28 +440,6 @@ static int m41t80_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
static ssize_t flags_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
int val;
val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
if (val < 0)
return val;
return sprintf(buf, "%#x\n", val);
}
static DEVICE_ATTR_RO(flags);
static struct attribute *attrs[] = {
&dev_attr_flags.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
#ifdef CONFIG_COMMON_CLK
#define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw)
@ -912,13 +890,6 @@ static struct notifier_block wdt_notifier = {
*****************************************************************************
*/
static void m41t80_remove_sysfs_group(void *_dev)
{
struct device *dev = _dev;
sysfs_remove_group(&dev->kobj, &attr_group);
}
static int m41t80_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -927,6 +898,7 @@ static int m41t80_probe(struct i2c_client *client,
struct rtc_device *rtc = NULL;
struct rtc_time tm;
struct m41t80_data *m41t80_data = NULL;
bool wakeup_source = false;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK |
I2C_FUNC_SMBUS_BYTE_DATA)) {
@ -947,6 +919,10 @@ static int m41t80_probe(struct i2c_client *client,
m41t80_data->features = id->driver_data;
i2c_set_clientdata(client, m41t80_data);
#ifdef CONFIG_OF
wakeup_source = of_property_read_bool(client->dev.of_node,
"wakeup-source");
#endif
if (client->irq > 0) {
rc = devm_request_threaded_irq(&client->dev, client->irq,
NULL, m41t80_handle_irq,
@ -955,14 +931,16 @@ static int m41t80_probe(struct i2c_client *client,
if (rc) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
client->irq = 0;
} else {
m41t80_rtc_ops.read_alarm = m41t80_read_alarm;
m41t80_rtc_ops.set_alarm = m41t80_set_alarm;
m41t80_rtc_ops.alarm_irq_enable = m41t80_alarm_irq_enable;
/* Enable the wakealarm */
device_init_wakeup(&client->dev, true);
wakeup_source = false;
}
}
if (client->irq > 0 || wakeup_source) {
m41t80_rtc_ops.read_alarm = m41t80_read_alarm;
m41t80_rtc_ops.set_alarm = m41t80_set_alarm;
m41t80_rtc_ops.alarm_irq_enable = m41t80_alarm_irq_enable;
/* Enable the wakealarm */
device_init_wakeup(&client->dev, true);
}
rtc = devm_rtc_device_register(&client->dev, client->name,
&m41t80_rtc_ops, THIS_MODULE);
@ -970,6 +948,10 @@ static int m41t80_probe(struct i2c_client *client,
return PTR_ERR(rtc);
m41t80_data->rtc = rtc;
if (client->irq <= 0) {
/* We cannot support UIE mode if we do not have an IRQ line */
rtc->uie_unsupported = 1;
}
/* Make sure HT (Halt Update) bit is cleared */
rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR);
@ -1004,21 +986,6 @@ static int m41t80_probe(struct i2c_client *client,
return rc;
}
/* Export sysfs entries */
rc = sysfs_create_group(&(&client->dev)->kobj, &attr_group);
if (rc) {
dev_err(&client->dev, "Failed to create sysfs group: %d\n", rc);
return rc;
}
rc = devm_add_action_or_reset(&client->dev, m41t80_remove_sysfs_group,
&client->dev);
if (rc) {
dev_err(&client->dev,
"Failed to add sysfs cleanup action: %d\n", rc);
return rc;
}
#ifdef CONFIG_RTC_DRV_M41T80_WDT
if (m41t80_data->features & M41T80_FEATURE_HT) {
save_client = client;

View File

@ -226,7 +226,7 @@ max6900_probe(struct i2c_client *client, const struct i2c_device_id *id)
return 0;
}
static struct i2c_device_id max6900_id[] = {
static const struct i2c_device_id max6900_id[] = {
{ "max6900", 0 },
{ }
};

View File

@ -234,8 +234,6 @@ static int max8925_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
else
ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x0);
if (ret < 0)
goto out;
out:
return ret;
}

View File

@ -238,26 +238,6 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
/*
* Clear all interrupts and release the IRQ
*/
static void mxc_rtc_release(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
void __iomem *ioaddr = pdata->ioaddr;
spin_lock_irq(&pdata->rtc->irq_lock);
/* Disable all rtc interrupts */
writew(0, ioaddr + RTC_RTCIENR);
/* Clear all interrupt status */
writew(0xffffffff, ioaddr + RTC_RTCISR);
spin_unlock_irq(&pdata->rtc->irq_lock);
}
static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
mxc_rtc_irq_enable(dev, RTC_ALM_BIT, enabled);
@ -343,7 +323,6 @@ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
/* RTC layer */
static const struct rtc_class_ops mxc_rtc_ops = {
.release = mxc_rtc_release,
.read_time = mxc_rtc_read_time,
.set_mmss64 = mxc_rtc_set_mmss,
.read_alarm = mxc_rtc_read_alarm,

View File

@ -157,49 +157,7 @@ static int puv3_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
static int puv3_rtc_open(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
int ret;
ret = request_irq(puv3_rtc_alarmno, puv3_rtc_alarmirq,
0, "pkunity-rtc alarm", rtc_dev);
if (ret) {
dev_err(dev, "IRQ%d error %d\n", puv3_rtc_alarmno, ret);
return ret;
}
ret = request_irq(puv3_rtc_tickno, puv3_rtc_tickirq,
0, "pkunity-rtc tick", rtc_dev);
if (ret) {
dev_err(dev, "IRQ%d error %d\n", puv3_rtc_tickno, ret);
goto tick_err;
}
return ret;
tick_err:
free_irq(puv3_rtc_alarmno, rtc_dev);
return ret;
}
static void puv3_rtc_release(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
/* do not clear AIE here, it may be needed for wake */
puv3_rtc_setpie(dev, 0);
free_irq(puv3_rtc_alarmno, rtc_dev);
free_irq(puv3_rtc_tickno, rtc_dev);
}
static const struct rtc_class_ops puv3_rtcops = {
.open = puv3_rtc_open,
.release = puv3_rtc_release,
.read_time = puv3_rtc_gettime,
.set_time = puv3_rtc_settime,
.read_alarm = puv3_rtc_getalarm,
@ -222,10 +180,6 @@ static void puv3_rtc_enable(struct device *dev, int en)
static int puv3_rtc_remove(struct platform_device *dev)
{
struct rtc_device *rtc = platform_get_drvdata(dev);
rtc_device_unregister(rtc);
puv3_rtc_setpie(&dev->dev, 0);
puv3_rtc_setaie(&dev->dev, 0);
@ -259,6 +213,24 @@ static int puv3_rtc_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "PKUnity_rtc: tick irq %d, alarm irq %d\n",
puv3_rtc_tickno, puv3_rtc_alarmno);
rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
ret = devm_request_irq(&pdev->dev, puv3_rtc_alarmno, puv3_rtc_alarmirq,
0, "pkunity-rtc alarm", rtc);
if (ret) {
dev_err(&pdev->dev, "IRQ%d error %d\n", puv3_rtc_alarmno, ret);
return ret;
}
ret = devm_request_irq(&pdev->dev, puv3_rtc_tickno, puv3_rtc_tickirq,
0, "pkunity-rtc tick", rtc);
if (ret) {
dev_err(&pdev->dev, "IRQ%d error %d\n", puv3_rtc_tickno, ret);
return ret;
}
/* get the memory region */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
@ -278,12 +250,10 @@ static int puv3_rtc_probe(struct platform_device *pdev)
puv3_rtc_enable(&pdev->dev, 1);
/* register RTC and exit */
rtc = rtc_device_register("pkunity", &pdev->dev, &puv3_rtcops,
THIS_MODULE);
if (IS_ERR(rtc)) {
rtc->ops = &puv3_rtcops;
ret = rtc_register_device(rtc);
if (ret) {
dev_err(&pdev->dev, "cannot attach rtc\n");
ret = PTR_ERR(rtc);
goto err_nortc;
}

View File

@ -348,7 +348,7 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
dev_err(dev, "No alarm IRQ resource defined\n");
return -ENXIO;
}
pxa_rtc_open(dev);
pxa_rtc->base = devm_ioremap(dev, pxa_rtc->ress->start,
resource_size(pxa_rtc->ress));
if (!pxa_rtc->base) {
@ -356,6 +356,8 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
}
pxa_rtc_open(dev);
sa1100_rtc->rcnr = pxa_rtc->base + 0x0;
sa1100_rtc->rtsr = pxa_rtc->base + 0x8;
sa1100_rtc->rtar = pxa_rtc->base + 0x4;

242
drivers/rtc/rtc-rtd119x.c Normal file
View File

@ -0,0 +1,242 @@
/*
* Realtek RTD129x RTC
*
* Copyright (c) 2017 Andreas Färber
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/spinlock.h>
#define RTD_RTCSEC 0x00
#define RTD_RTCMIN 0x04
#define RTD_RTCHR 0x08
#define RTD_RTCDATE1 0x0c
#define RTD_RTCDATE2 0x10
#define RTD_RTCACR 0x28
#define RTD_RTCEN 0x2c
#define RTD_RTCCR 0x30
#define RTD_RTCSEC_RTCSEC_MASK 0x7f
#define RTD_RTCMIN_RTCMIN_MASK 0x3f
#define RTD_RTCHR_RTCHR_MASK 0x1f
#define RTD_RTCDATE1_RTCDATE1_MASK 0xff
#define RTD_RTCDATE2_RTCDATE2_MASK 0x7f
#define RTD_RTCACR_RTCPWR BIT(7)
#define RTD_RTCEN_RTCEN_MASK 0xff
#define RTD_RTCCR_RTCRST BIT(6)
struct rtd119x_rtc {
void __iomem *base;
struct clk *clk;
struct rtc_device *rtcdev;
unsigned int base_year;
};
static inline int rtd119x_rtc_days_in_year(int year)
{
return 365 + (is_leap_year(year) ? 1 : 0);
}
static void rtd119x_rtc_reset(struct device *dev)
{
struct rtd119x_rtc *data = dev_get_drvdata(dev);
u32 val;
val = readl_relaxed(data->base + RTD_RTCCR);
val |= RTD_RTCCR_RTCRST;
writel_relaxed(val, data->base + RTD_RTCCR);
val &= ~RTD_RTCCR_RTCRST;
writel(val, data->base + RTD_RTCCR);
}
static void rtd119x_rtc_set_enabled(struct device *dev, bool enable)
{
struct rtd119x_rtc *data = dev_get_drvdata(dev);
u32 val;
val = readl_relaxed(data->base + RTD_RTCEN);
if (enable) {
if ((val & RTD_RTCEN_RTCEN_MASK) == 0x5a)
return;
writel_relaxed(0x5a, data->base + RTD_RTCEN);
} else {
writel_relaxed(0, data->base + RTD_RTCEN);
}
}
static int rtd119x_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct rtd119x_rtc *data = dev_get_drvdata(dev);
s32 day;
u32 sec;
unsigned int year;
int tries = 0;
while (true) {
tm->tm_sec = (readl_relaxed(data->base + RTD_RTCSEC) & RTD_RTCSEC_RTCSEC_MASK) >> 1;
tm->tm_min = readl_relaxed(data->base + RTD_RTCMIN) & RTD_RTCMIN_RTCMIN_MASK;
tm->tm_hour = readl_relaxed(data->base + RTD_RTCHR) & RTD_RTCHR_RTCHR_MASK;
day = readl_relaxed(data->base + RTD_RTCDATE1) & RTD_RTCDATE1_RTCDATE1_MASK;
day |= (readl_relaxed(data->base + RTD_RTCDATE2) & RTD_RTCDATE2_RTCDATE2_MASK) << 8;
sec = (readl_relaxed(data->base + RTD_RTCSEC) & RTD_RTCSEC_RTCSEC_MASK) >> 1;
tries++;
if (sec == tm->tm_sec)
break;
if (tries >= 3)
return -EINVAL;
}
if (tries > 1)
dev_dbg(dev, "%s: needed %i tries\n", __func__, tries);
year = data->base_year;
while (day >= rtd119x_rtc_days_in_year(year)) {
day -= rtd119x_rtc_days_in_year(year);
year++;
}
tm->tm_year = year - 1900;
tm->tm_yday = day;
tm->tm_mon = 0;
while (day >= rtc_month_days(tm->tm_mon, year)) {
day -= rtc_month_days(tm->tm_mon, year);
tm->tm_mon++;
}
tm->tm_mday = day + 1;
return 0;
}
static int rtd119x_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct rtd119x_rtc *data = dev_get_drvdata(dev);
unsigned int day;
int i;
if (1900 + tm->tm_year < data->base_year)
return -EINVAL;
day = 0;
for (i = data->base_year; i < 1900 + tm->tm_year; i++)
day += rtd119x_rtc_days_in_year(i);
day += tm->tm_yday;
if (day > 0x7fff)
return -EINVAL;
rtd119x_rtc_set_enabled(dev, false);
writel_relaxed((tm->tm_sec << 1) & RTD_RTCSEC_RTCSEC_MASK, data->base + RTD_RTCSEC);
writel_relaxed(tm->tm_min & RTD_RTCMIN_RTCMIN_MASK, data->base + RTD_RTCMIN);
writel_relaxed(tm->tm_hour & RTD_RTCHR_RTCHR_MASK, data->base + RTD_RTCHR);
writel_relaxed(day & RTD_RTCDATE1_RTCDATE1_MASK, data->base + RTD_RTCDATE1);
writel_relaxed((day >> 8) & RTD_RTCDATE2_RTCDATE2_MASK, data->base + RTD_RTCDATE2);
rtd119x_rtc_set_enabled(dev, true);
return 0;
}
static const struct rtc_class_ops rtd119x_rtc_ops = {
.read_time = rtd119x_rtc_read_time,
.set_time = rtd119x_rtc_set_time,
};
static const struct of_device_id rtd119x_rtc_dt_ids[] = {
{ .compatible = "realtek,rtd1295-rtc" },
{ }
};
static int rtd119x_rtc_probe(struct platform_device *pdev)
{
struct rtd119x_rtc *data;
struct resource *res;
u32 val;
int ret;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
platform_set_drvdata(pdev, data);
data->base_year = 2014;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
data->clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
ret = clk_prepare_enable(data->clk);
if (ret) {
clk_put(data->clk);
return ret;
}
val = readl_relaxed(data->base + RTD_RTCACR);
if (!(val & RTD_RTCACR_RTCPWR)) {
writel_relaxed(RTD_RTCACR_RTCPWR, data->base + RTD_RTCACR);
rtd119x_rtc_reset(&pdev->dev);
writel_relaxed(0, data->base + RTD_RTCMIN);
writel_relaxed(0, data->base + RTD_RTCHR);
writel_relaxed(0, data->base + RTD_RTCDATE1);
writel_relaxed(0, data->base + RTD_RTCDATE2);
}
rtd119x_rtc_set_enabled(&pdev->dev, true);
data->rtcdev = devm_rtc_device_register(&pdev->dev, "rtc",
&rtd119x_rtc_ops, THIS_MODULE);
if (IS_ERR(data->rtcdev)) {
dev_err(&pdev->dev, "failed to register rtc device");
clk_disable_unprepare(data->clk);
clk_put(data->clk);
return PTR_ERR(data->rtcdev);
}
return 0;
}
static int rtd119x_rtc_remove(struct platform_device *pdev)
{
struct rtd119x_rtc *data = platform_get_drvdata(pdev);
rtd119x_rtc_set_enabled(&pdev->dev, false);
clk_disable_unprepare(data->clk);
clk_put(data->clk);
return 0;
}
static struct platform_driver rtd119x_rtc_driver = {
.probe = rtd119x_rtc_probe,
.remove = rtd119x_rtc_remove,
.driver = {
.name = "rtd1295-rtc",
.of_match_table = rtd119x_rtc_dt_ids,
},
};
builtin_platform_driver(rtd119x_rtc_driver);

View File

@ -868,7 +868,7 @@ static int rv3029_i2c_probe(struct i2c_client *client,
return rv3029_probe(&client->dev, regmap, client->irq, client->name);
}
static struct i2c_device_id rv3029_id[] = {
static const struct i2c_device_id rv3029_id[] = {
{ "rv3029", 0 },
{ "rv3029c2", 0 },
{ }

View File

@ -106,33 +106,12 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
return 0;
}
/*
* Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
* To keep the information if an irq is pending, pass the value read from
* STATUS1 to the caller.
*/
static int s35390a_reset(struct s35390a *s35390a, char *status1)
static int s35390a_init(struct s35390a *s35390a)
{
char buf;
int ret;
unsigned initcount = 0;
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
if (ret < 0)
return ret;
if (*status1 & S35390A_FLAG_POC)
/*
* Do not communicate for 0.5 seconds since the power-on
* detection circuit is in operation.
*/
msleep(500);
else if (!(*status1 & S35390A_FLAG_BLD))
/*
* If both POC and BLD are unset everything is fine.
*/
return 0;
/*
* At least one of POC and BLD are set, so reinitialise chip. Keeping
* this information in the hardware to know later that the time isn't
@ -142,7 +121,6 @@ static int s35390a_reset(struct s35390a *s35390a, char *status1)
* The 24H bit is kept over reset, so set it already here.
*/
initialize:
*status1 = S35390A_FLAG_24H;
buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
@ -165,6 +143,34 @@ initialize:
return 1;
}
/*
* Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
* To keep the information if an irq is pending, pass the value read from
* STATUS1 to the caller.
*/
static int s35390a_read_status(struct s35390a *s35390a, char *status1)
{
int ret;
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
if (ret < 0)
return ret;
if (*status1 & S35390A_FLAG_POC) {
/*
* Do not communicate for 0.5 seconds since the power-on
* detection circuit is in operation.
*/
msleep(500);
return 1;
} else if (*status1 & S35390A_FLAG_BLD)
return 1;
/*
* If both POC and BLD are unset everything is fine.
*/
return 0;
}
static int s35390a_disable_test_mode(struct s35390a *s35390a)
{
char buf[1];
@ -208,13 +214,16 @@ static int s35390a_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct s35390a *s35390a = i2c_get_clientdata(client);
int i, err;
char buf[7];
char buf[7], status;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d mday=%d, "
"mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec,
tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year,
tm->tm_wday);
if (s35390a_read_status(s35390a, &status) == 1)
s35390a_init(s35390a);
buf[S35390A_BYTE_YEAR] = bin2bcd(tm->tm_year - 100);
buf[S35390A_BYTE_MONTH] = bin2bcd(tm->tm_mon + 1);
buf[S35390A_BYTE_DAY] = bin2bcd(tm->tm_mday);
@ -235,9 +244,12 @@ static int s35390a_set_datetime(struct i2c_client *client, struct rtc_time *tm)
static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct s35390a *s35390a = i2c_get_clientdata(client);
char buf[7];
char buf[7], status;
int i, err;
if (s35390a_read_status(s35390a, &status) == 1)
return -EINVAL;
err = s35390a_get_reg(s35390a, S35390A_CMD_TIME1, buf, sizeof(buf));
if (err < 0)
return err;
@ -392,12 +404,42 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm)
return s35390a_set_datetime(to_i2c_client(dev), tm);
}
static int s35390a_rtc_ioctl(struct device *dev, unsigned int cmd,
unsigned long arg)
{
struct i2c_client *client = to_i2c_client(dev);
struct s35390a *s35390a = i2c_get_clientdata(client);
char sts;
int err;
switch (cmd) {
case RTC_VL_READ:
/* s35390a_reset set lowvoltage flag and init RTC if needed */
err = s35390a_read_status(s35390a, &sts);
if (err < 0)
return err;
if (copy_to_user((void __user *)arg, &err, sizeof(int)))
return -EFAULT;
break;
case RTC_VL_CLR:
/* update flag and clear register */
err = s35390a_init(s35390a);
if (err < 0)
return err;
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
static const struct rtc_class_ops s35390a_rtc_ops = {
.read_time = s35390a_rtc_read_time,
.set_time = s35390a_rtc_set_time,
.set_alarm = s35390a_rtc_set_alarm,
.read_alarm = s35390a_rtc_read_alarm,
.ioctl = s35390a_rtc_ioctl,
};
static struct i2c_driver s35390a_driver;
@ -405,7 +447,7 @@ static struct i2c_driver s35390a_driver;
static int s35390a_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err, err_reset;
int err, err_read;
unsigned int i;
struct s35390a *s35390a;
struct rtc_time tm;
@ -438,9 +480,9 @@ static int s35390a_probe(struct i2c_client *client,
}
}
err_reset = s35390a_reset(s35390a, &status1);
if (err_reset < 0) {
err = err_reset;
err_read = s35390a_read_status(s35390a, &status1);
if (err_read < 0) {
err = err_read;
dev_err(&client->dev, "error resetting chip\n");
goto exit_dummy;
}
@ -466,7 +508,7 @@ static int s35390a_probe(struct i2c_client *client,
}
}
if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
if (err_read > 0 || s35390a_get_datetime(client, &tm) < 0)
dev_warn(&client->dev, "clock needs to be set\n");
device_set_wakeup_capable(&client->dev, 1);

View File

@ -95,46 +95,6 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int sa1100_rtc_open(struct device *dev)
{
struct sa1100_rtc *info = dev_get_drvdata(dev);
struct rtc_device *rtc = info->rtc;
int ret;
ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz);
goto fail_ui;
}
ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, 0, "rtc Alrm", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", info->irq_alarm);
goto fail_ai;
}
rtc->max_user_freq = RTC_FREQ;
rtc_irq_set_freq(rtc, NULL, RTC_FREQ);
return 0;
fail_ai:
free_irq(info->irq_1hz, dev);
fail_ui:
clk_disable_unprepare(info->clk);
return ret;
}
static void sa1100_rtc_release(struct device *dev)
{
struct sa1100_rtc *info = dev_get_drvdata(dev);
spin_lock_irq(&info->lock);
writel_relaxed(0, info->rtsr);
spin_unlock_irq(&info->lock);
free_irq(info->irq_alarm, dev);
free_irq(info->irq_1hz, dev);
}
static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
u32 rtsr;
@ -216,8 +176,6 @@ static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
}
static const struct rtc_class_ops sa1100_rtc_ops = {
.open = sa1100_rtc_open,
.release = sa1100_rtc_release,
.read_time = sa1100_rtc_read_time,
.set_time = sa1100_rtc_set_time,
.read_alarm = sa1100_rtc_read_alarm,
@ -265,6 +223,9 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info)
}
info->rtc = rtc;
rtc->max_user_freq = RTC_FREQ;
rtc_irq_set_freq(rtc, NULL, RTC_FREQ);
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
* See also the comments in sa1100_rtc_interrupt().
*
@ -299,6 +260,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
struct resource *iores;
void __iomem *base;
int irq_1hz, irq_alarm;
int ret;
irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz");
irq_alarm = platform_get_irq_byname(pdev, "rtc alarm");
@ -311,6 +273,19 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
info->irq_1hz = irq_1hz;
info->irq_alarm = irq_alarm;
ret = devm_request_irq(&pdev->dev, irq_1hz, sa1100_rtc_interrupt, 0,
"rtc 1Hz", &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "IRQ %d already in use.\n", irq_1hz);
return ret;
}
ret = devm_request_irq(&pdev->dev, irq_alarm, sa1100_rtc_interrupt, 0,
"rtc Alrm", &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "IRQ %d already in use.\n", irq_alarm);
return ret;
}
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(base))
@ -339,8 +314,12 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
{
struct sa1100_rtc *info = platform_get_drvdata(pdev);
if (info)
if (info) {
spin_lock_irq(&info->lock);
writel_relaxed(0, info->rtsr);
spin_unlock_irq(&info->lock);
clk_disable_unprepare(info->clk);
}
return 0;
}

View File

@ -73,6 +73,9 @@
#define SUN6I_ALARM_CONFIG 0x0050
#define SUN6I_ALARM_CONFIG_WAKEUP BIT(0)
#define SUN6I_LOSC_OUT_GATING 0x0060
#define SUN6I_LOSC_OUT_GATING_EN BIT(0)
/*
* Get date values
*/
@ -125,6 +128,7 @@ struct sun6i_rtc_dev {
struct clk_hw hw;
struct clk_hw *int_osc;
struct clk *losc;
struct clk *ext_losc;
spinlock_t lock;
};
@ -188,23 +192,24 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
struct clk_init_data init = {
.ops = &sun6i_rtc_osc_ops,
};
const char *clkout_name = "osc32k-out";
const char *parents[2];
rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return;
spin_lock_init(&rtc->lock);
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws),
clk_data = kzalloc(sizeof(*clk_data) + (sizeof(*clk_data->hws) * 2),
GFP_KERNEL);
if (!clk_data)
return;
spin_lock_init(&rtc->lock);
rtc->base = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(rtc->base)) {
pr_crit("Can't map RTC registers");
return;
goto err;
}
/* Switch to the external, more precise, oscillator */
@ -216,7 +221,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
/* Deal with old DTs */
if (!of_get_property(node, "clocks", NULL))
return;
goto err;
rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL,
"rtc-int-osc",
@ -235,7 +240,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
init.parent_names = parents;
init.num_parents = of_clk_get_parent_count(node) + 1;
of_property_read_string(node, "clock-output-names", &init.name);
of_property_read_string_index(node, "clock-output-names", 0,
&init.name);
rtc->losc = clk_register(NULL, &rtc->hw);
if (IS_ERR(rtc->losc)) {
@ -243,9 +249,25 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
return;
}
clk_data->num = 1;
of_property_read_string_index(node, "clock-output-names", 1,
&clkout_name);
rtc->ext_losc = clk_register_gate(NULL, clkout_name, rtc->hw.init->name,
0, rtc->base + SUN6I_LOSC_OUT_GATING,
SUN6I_LOSC_OUT_GATING_EN, 0,
&rtc->lock);
if (IS_ERR(rtc->ext_losc)) {
pr_crit("Couldn't register the LOSC external gate\n");
return;
}
clk_data->num = 2;
clk_data->hws[0] = &rtc->hw;
clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
return;
err:
kfree(clk_data);
}
CLK_OF_DECLARE_DRIVER(sun6i_rtc_clk, "allwinner,sun6i-a31-rtc",
sun6i_rtc_clk_init);

View File

@ -119,23 +119,6 @@ static inline void write_elapsed_second(unsigned long sec)
spin_unlock_irq(&rtc_lock);
}
static void vr41xx_rtc_release(struct device *dev)
{
spin_lock_irq(&rtc_lock);
rtc1_write(ECMPLREG, 0);
rtc1_write(ECMPMREG, 0);
rtc1_write(ECMPHREG, 0);
rtc1_write(RTCL1LREG, 0);
rtc1_write(RTCL1HREG, 0);
spin_unlock_irq(&rtc_lock);
disable_irq(aie_irq);
disable_irq(pie_irq);
}
static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time)
{
unsigned long epoch_sec, elapsed_sec;
@ -272,7 +255,6 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
}
static const struct rtc_class_ops vr41xx_rtc_ops = {
.release = vr41xx_rtc_release,
.ioctl = vr41xx_rtc_ioctl,
.read_time = vr41xx_rtc_read_time,
.set_time = vr41xx_rtc_set_time,

View File

@ -72,8 +72,6 @@ extern struct class *rtc_class;
* issued through ioctl() ...
*/
struct rtc_class_ops {
int (*open)(struct device *);
void (*release)(struct device *);
int (*ioctl)(struct device *, unsigned int, unsigned long);
int (*read_time)(struct device *, struct rtc_time *);
int (*set_time)(struct device *, struct rtc_time *);