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:
commit
561a8eb3e1
@ -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
|
||||
--------
|
||||
|
@ -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>;
|
||||
};
|
@ -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.
|
||||
|
16
Documentation/devicetree/bindings/rtc/realtek,rtd119x.txt
Normal file
16
Documentation/devicetree/bindings/rtc/realtek,rtd119x.txt
Normal 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>;
|
||||
};
|
@ -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>;
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
@ -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
237
drivers/rtc/rtc-goldfish.c
Normal 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);
|
@ -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;
|
||||
|
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
242
drivers/rtc/rtc-rtd119x.c
Normal 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);
|
@ -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 },
|
||||
{ }
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user