RTC for 4.10

Subsystem:
  - non-modular drivers are now explicitly non-modular
 
 New driver:
  - Epson Toyocom rtc-7301sf/dg
 
 Drivers:
  - cmos: reject unsupported alarm values wrt the RTC capabilities
  - ds1307: ACPI support
  - jz4740: DT support, jz4780 handling, can now be used as a system power
  controller
  - mcp795: many fixes, in particular proper month handling
  - twl: driver is now DT only
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEl0I5XWmUIrwBfFMm2KKDO9oT4sIFAlhXIxkACgkQ2KKDO9oT
 4sKJIQ/+MxwjMs0CZ8744orSTkX5AJTOwGcwg+SEmp23Ht0nV0SCrAkkndC3HamM
 9MwT0qVmL2rgiqyeSRAjdVVIt+UFJeGXMuBhc5UBqSomjXIqfN9nA0DXuddKx/at
 ZwWtPIN4HyWS5Uetn/FTXC9scBa5+2bJEYdB3ocC/QNgcCErINzPBJZEsduaxajK
 AUIOhHPWn9D2cDzIxPMplPyVSWXUI3WXiF2mvgi/VAB21StQoKY6KkJV+u6Q+56t
 IdJeKaAP+bF535T66wl/yY1KNhkRwF6M0qFs+qR5htoxzS6zx6hW+aRibvrIAP3/
 YiAQj2L7hOjW1ky0H1rEUpjTYFxWmOx2AWZJ3ubxzveF6pz0Qn1TTrzOHVkelaHB
 iuuYrxXMmC84qmHrxIdrkZdH2eu2Fm12/D1VME6bjdD4BApkEHjKebGVS4F9XaMi
 Pdbb4olEslZL+XEZXkuqmopl7g1/Wf34IrCskNDoUx7t+JsCjrA+hXMVeqwl3e8m
 Edcv103l1Wkivv9kHZEgx8IwOeti5d77z+QUvQzHYKK28o8zQii/3zlvQzJ/6gnE
 M20vRv7cptVL4GmZd4ebFB2GOUteSfnOJJAwKZ3ipbZaGtNSs1nhAqTpg9uw4OEr
 rPlRJJw5Cov1ctV+dBuVhLmzStBg3PJj2fkZ4qjdYgeiu2wZAV0=
 =z4SX
 -----END PGP SIGNATURE-----

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

Pull RTC updates from Alexandre Belloni:
  "Subsystem:
   - non-modular drivers are now explicitly non-modular

  New driver:
    - Epson Toyocom rtc-7301sf/dg

  Drivers:
   - cmos: reject unsupported alarm values wrt the RTC capabilities
   - ds1307: ACPI support
   - jz4740: DT support, jz4780 handling, can now be used as a system
     power controller
   - mcp795: many fixes, in particular proper month handling
   - twl: driver is now DT only"

* tag 'rtc-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (31 commits)
  rtc: mcp795: Fix whitespace and indentation.
  rtc: mcp795: Prefer using the BIT() macro.
  rtc: mcp795: fix month write resetting date to 1.
  rtc: mcp795: fix time range difference between linux and RTC chip.
  rtc: mcp795: fix bitmask value for leap year (LP).
  rtc: mcp795: use bcd2bin/bin2bcd.
  rtc: add support for EPSON TOYOCOM RTC-7301SF/DG
  rtc: ds1307: Add ACPI support
  rtc: imxdi: (trivial) fix a typo
  rtc: ds1374: Merge conditional + WARN_ON()
  rtc: twl: make driver DT only
  rtc: twl: kill static variables
  rtc: fix typos in Kconfig
  rtc: jz4740: make the driver builtin only
  rtc: jz4740: remove unused EXPORT_SYMBOL
  Documentation: bindings: fix twl-rtc documentation
  rtc: Enable compile testing for Maxim and Samsung drivers
  MIPS: jz4740: Remove obsolete code
  MIPS: qi_lb60: Probe RTC driver from DT and use it as power controller
  MIPS: jz4740: DTS: Probe the jz4740-rtc driver from devicetree
  ...
This commit is contained in:
Linus Torvalds 2016-12-18 18:18:03 -08:00
commit b0b3a37b90
24 changed files with 1054 additions and 256 deletions

View File

@ -1,8 +1,9 @@
What: Attribute for calibrating ST-Ericsson AB8500 Real Time Clock What: /sys/class/rtc/rtc0/device/rtc_calibration
Date: Oct 2011 Date: Oct 2011
KernelVersion: 3.0 KernelVersion: 3.0
Contact: Mark Godfrey <mark.godfrey@stericsson.com> Contact: Mark Godfrey <mark.godfrey@stericsson.com>
Description: The rtc_calibration attribute allows the userspace to Description: Attribute for calibrating ST-Ericsson AB8500 Real Time Clock
The rtc_calibration attribute allows the userspace to
calibrate the AB8500.s 32KHz Real Time Clock. calibrate the AB8500.s 32KHz Real Time Clock.
Every 60 seconds the AB8500 will correct the RTC's value Every 60 seconds the AB8500 will correct the RTC's value
by adding to it the value of this attribute. by adding to it the value of this attribute.

View File

@ -0,0 +1,16 @@
EPSON TOYOCOM RTC-7301SF/DG
Required properties:
- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg"
- reg: Specifies base physical address and size of the registers.
- interrupts: A single interrupt specifier.
Example:
rtc: rtc@44a00000 {
compatible = "epson,rtc7301dg";
reg = <0x44a00000 0x10000>;
interrupt-parent = <&axi_intc_0>;
interrupts = <3 2>;
};

View File

@ -0,0 +1,37 @@
JZ4740 and similar SoCs real-time clock driver
Required properties:
- compatible: One of:
- "ingenic,jz4740-rtc" - for use with the JZ4740 SoC
- "ingenic,jz4780-rtc" - for use with the JZ4780 SoC
- reg: Address range of rtc register set
- interrupts: IRQ number for the alarm interrupt
- clocks: phandle to the "rtc" clock
- clock-names: must be "rtc"
Optional properties:
- system-power-controller: To use this component as the
system power controller
- reset-pin-assert-time-ms: Reset pin low-level assertion
time after wakeup (default 60ms; range 0-125ms if RTC clock
at 32 kHz)
- min-wakeup-pin-assert-time-ms: Minimum wakeup pin assertion
time (default 100ms; range 0-2s if RTC clock at 32 kHz)
Example:
rtc@10003000 {
compatible = "ingenic,jz4740-rtc";
reg = <0x10003000 0x40>;
interrupt-parent = <&intc>;
interrupts = <32>;
clocks = <&rtc_clock>;
clock-names = "rtc";
system-power-controller;
reset-pin-assert-time-ms = <60>;
min-wakeup-pin-assert-time-ms = <100>;
};

View File

@ -1,12 +1,11 @@
* TI twl RTC * Texas Instruments TWL4030/6030 RTC
The TWL family (twl4030/6030) contains a RTC.
Required properties: Required properties:
- compatible : Should be twl4030-rtc - compatible : Should be "ti,twl4030-rtc"
- interrupts : Should be the interrupt number.
Examples: Example:
rtc {
rtc@0 { compatible = "ti,twl4030-rtc";
compatible = "ti,twl4030-rtc"; interrupts = <11>;
}; };

View File

@ -44,6 +44,17 @@
#clock-cells = <1>; #clock-cells = <1>;
}; };
rtc_dev: rtc@10003000 {
compatible = "ingenic,jz4740-rtc";
reg = <0x10003000 0x40>;
interrupt-parent = <&intc>;
interrupts = <15>;
clocks = <&cgu JZ4740_CLK_RTC>;
clock-names = "rtc";
};
uart0: serial@10030000 { uart0: serial@10030000 {
compatible = "ingenic,jz4740-uart"; compatible = "ingenic,jz4740-uart";
reg = <0x10030000 0x100>; reg = <0x10030000 0x100>;

View File

@ -13,3 +13,7 @@
&ext { &ext {
clock-frequency = <12000000>; clock-frequency = <12000000>;
}; };
&rtc_dev {
system-power-controller;
};

View File

@ -22,7 +22,6 @@
extern struct platform_device jz4740_udc_device; extern struct platform_device jz4740_udc_device;
extern struct platform_device jz4740_udc_xceiv_device; extern struct platform_device jz4740_udc_xceiv_device;
extern struct platform_device jz4740_mmc_device; extern struct platform_device jz4740_mmc_device;
extern struct platform_device jz4740_rtc_device;
extern struct platform_device jz4740_i2c_device; extern struct platform_device jz4740_i2c_device;
extern struct platform_device jz4740_nand_device; extern struct platform_device jz4740_nand_device;
extern struct platform_device jz4740_framebuffer_device; extern struct platform_device jz4740_framebuffer_device;

View File

@ -438,7 +438,6 @@ static struct platform_device *jz_platform_devices[] __initdata = {
&jz4740_pcm_device, &jz4740_pcm_device,
&jz4740_i2s_device, &jz4740_i2s_device,
&jz4740_codec_device, &jz4740_codec_device,
&jz4740_rtc_device,
&jz4740_adc_device, &jz4740_adc_device,
&jz4740_pwm_device, &jz4740_pwm_device,
&jz4740_dma_device, &jz4740_dma_device,

View File

@ -88,27 +88,6 @@ struct platform_device jz4740_mmc_device = {
.resource = jz4740_mmc_resources, .resource = jz4740_mmc_resources,
}; };
/* RTC controller */
static struct resource jz4740_rtc_resources[] = {
{
.start = JZ4740_RTC_BASE_ADDR,
.end = JZ4740_RTC_BASE_ADDR + 0x38 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = JZ4740_IRQ_RTC,
.end = JZ4740_IRQ_RTC,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device jz4740_rtc_device = {
.name = "jz4740-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(jz4740_rtc_resources),
.resource = jz4740_rtc_resources,
};
/* I2C controller */ /* I2C controller */
static struct resource jz4740_i2c_resources[] = { static struct resource jz4740_i2c_resources[] = {
{ {

View File

@ -57,71 +57,8 @@ static void jz4740_restart(char *command)
jz4740_halt(); jz4740_halt();
} }
#define JZ_REG_RTC_CTRL 0x00
#define JZ_REG_RTC_HIBERNATE 0x20
#define JZ_REG_RTC_WAKEUP_FILTER 0x24
#define JZ_REG_RTC_RESET_COUNTER 0x28
#define JZ_RTC_CTRL_WRDY BIT(7)
#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0
static inline void jz4740_rtc_wait_ready(void __iomem *rtc_base)
{
uint32_t ctrl;
do {
ctrl = readl(rtc_base + JZ_REG_RTC_CTRL);
} while (!(ctrl & JZ_RTC_CTRL_WRDY));
}
static void jz4740_power_off(void)
{
void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x38);
unsigned long wakeup_filter_ticks;
unsigned long reset_counter_ticks;
struct clk *rtc_clk;
unsigned long rtc_rate;
rtc_clk = clk_get(NULL, "rtc");
if (IS_ERR(rtc_clk))
panic("unable to get RTC clock");
rtc_rate = clk_get_rate(rtc_clk);
clk_put(rtc_clk);
/*
* Set minimum wakeup pin assertion time: 100 ms.
* Range is 0 to 2 sec if RTC is clocked at 32 kHz.
*/
wakeup_filter_ticks = (100 * rtc_rate) / 1000;
if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
else
wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
jz4740_rtc_wait_ready(rtc_base);
writel(wakeup_filter_ticks, rtc_base + JZ_REG_RTC_WAKEUP_FILTER);
/*
* Set reset pin low-level assertion time after wakeup: 60 ms.
* Range is 0 to 125 ms if RTC is clocked at 32 kHz.
*/
reset_counter_ticks = (60 * rtc_rate) / 1000;
if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
else
reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
jz4740_rtc_wait_ready(rtc_base);
writel(reset_counter_ticks, rtc_base + JZ_REG_RTC_RESET_COUNTER);
jz4740_rtc_wait_ready(rtc_base);
writel(1, rtc_base + JZ_REG_RTC_HIBERNATE);
jz4740_halt();
}
void jz4740_reset_init(void) void jz4740_reset_init(void)
{ {
_machine_restart = jz4740_restart; _machine_restart = jz4740_restart;
_machine_halt = jz4740_halt; _machine_halt = jz4740_halt;
pm_power_off = jz4740_power_off;
} }

View File

@ -303,7 +303,7 @@ config RTC_DRV_MAX6900
config RTC_DRV_MAX8907 config RTC_DRV_MAX8907
tristate "Maxim MAX8907" tristate "Maxim MAX8907"
depends on MFD_MAX8907 depends on MFD_MAX8907 || COMPILE_TEST
help help
If you say yes here you will get support for the If you say yes here you will get support for the
RTC of Maxim MAX8907 PMIC. RTC of Maxim MAX8907 PMIC.
@ -343,7 +343,7 @@ config RTC_DRV_MAX8997
config RTC_DRV_MAX77686 config RTC_DRV_MAX77686
tristate "Maxim MAX77686" tristate "Maxim MAX77686"
depends on MFD_MAX77686 || MFD_MAX77620 depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
help help
If you say yes here you will get support for the If you say yes here you will get support for the
RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC. RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC.
@ -481,6 +481,7 @@ config RTC_DRV_TWL92330
config RTC_DRV_TWL4030 config RTC_DRV_TWL4030
tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0" tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
depends on TWL4030_CORE depends on TWL4030_CORE
depends on OF
help help
If you say yes here you get support for the RTC on the If you say yes here you get support for the RTC on the
TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms. TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
@ -602,7 +603,8 @@ config RTC_DRV_RV8803
config RTC_DRV_S5M config RTC_DRV_S5M
tristate "Samsung S2M/S5M series" tristate "Samsung S2M/S5M series"
depends on MFD_SEC_CORE depends on MFD_SEC_CORE || COMPILE_TEST
select REGMAP_IRQ
help help
If you say yes here you will get support for the If you say yes here you will get support for the
RTC of Samsung S2MPS14 and S5M PMIC series. RTC of Samsung S2MPS14 and S5M PMIC series.
@ -820,8 +822,8 @@ config RTC_DRV_RV3029_HWMON
comment "Platform RTC drivers" comment "Platform RTC drivers"
# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h> # this 'CMOS' RTC driver is arch dependent because it requires
# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a # <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
# global rtc_lock ... it's not yet just another platform_device. # global rtc_lock ... it's not yet just another platform_device.
config RTC_DRV_CMOS config RTC_DRV_CMOS
@ -1549,14 +1551,11 @@ config RTC_DRV_MPC5121
will be called rtc-mpc5121. will be called rtc-mpc5121.
config RTC_DRV_JZ4740 config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC" bool "Ingenic JZ4740 SoC"
depends on MACH_JZ4740 || COMPILE_TEST depends on MACH_INGENIC || COMPILE_TEST
help help
If you say yes here you get support for the Ingenic JZ4740 SoC RTC If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
controller. controllers.
This driver can also be buillt as a module. If so, the module
will be called rtc-jz4740.
config RTC_DRV_LPC24XX config RTC_DRV_LPC24XX
tristate "NXP RTC for LPC178x/18xx/408x/43xx" tristate "NXP RTC for LPC178x/18xx/408x/43xx"
@ -1567,7 +1566,7 @@ config RTC_DRV_LPC24XX
NXP LPC178x/18xx/408x/43xx devices. NXP LPC178x/18xx/408x/43xx devices.
If you have one of the devices above enable this driver to use If you have one of the devices above enable this driver to use
the hardware RTC. This driver can also be buillt as a module. If the hardware RTC. This driver can also be built as a module. If
so, the module will be called rtc-lpc24xx. so, the module will be called rtc-lpc24xx.
config RTC_DRV_LPC32XX config RTC_DRV_LPC32XX
@ -1576,7 +1575,7 @@ config RTC_DRV_LPC32XX
help help
This enables support for the NXP RTC in the LPC32XX This enables support for the NXP RTC in the LPC32XX
This driver can also be buillt as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-lpc32xx. will be called rtc-lpc32xx.
config RTC_DRV_PM8XXX config RTC_DRV_PM8XXX
@ -1706,6 +1705,17 @@ config RTC_DRV_PIC32
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-pic32 will be called rtc-pic32
config RTC_DRV_R7301
tristate "EPSON TOYOCOM RTC-7301SF/DG"
select REGMAP_MMIO
depends on OF && HAS_IOMEM
help
If you say yes here you get support for the EPSON TOYOCOM
RTC-7301SF/DG chips.
This driver can also be built as a module. If so, the module
will be called rtc-r7301.
comment "HID Sensor RTC drivers" comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME config RTC_DRV_HID_SENSOR_TIME

View File

@ -120,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o

View File

@ -332,14 +332,86 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
cmos_checkintr(cmos, rtc_control); cmos_checkintr(cmos, rtc_control);
} }
static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
struct rtc_time now;
cmos_read_time(dev, &now);
if (!cmos->day_alrm) {
time64_t t_max_date;
time64_t t_alrm;
t_max_date = rtc_tm_to_time64(&now);
t_max_date += 24 * 60 * 60 - 1;
t_alrm = rtc_tm_to_time64(&t->time);
if (t_alrm > t_max_date) {
dev_err(dev,
"Alarms can be up to one day in the future\n");
return -EINVAL;
}
} else if (!cmos->mon_alrm) {
struct rtc_time max_date = now;
time64_t t_max_date;
time64_t t_alrm;
int max_mday;
if (max_date.tm_mon == 11) {
max_date.tm_mon = 0;
max_date.tm_year += 1;
} else {
max_date.tm_mon += 1;
}
max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
if (max_date.tm_mday > max_mday)
max_date.tm_mday = max_mday;
t_max_date = rtc_tm_to_time64(&max_date);
t_max_date -= 1;
t_alrm = rtc_tm_to_time64(&t->time);
if (t_alrm > t_max_date) {
dev_err(dev,
"Alarms can be up to one month in the future\n");
return -EINVAL;
}
} else {
struct rtc_time max_date = now;
time64_t t_max_date;
time64_t t_alrm;
int max_mday;
max_date.tm_year += 1;
max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year);
if (max_date.tm_mday > max_mday)
max_date.tm_mday = max_mday;
t_max_date = rtc_tm_to_time64(&max_date);
t_max_date -= 1;
t_alrm = rtc_tm_to_time64(&t->time);
if (t_alrm > t_max_date) {
dev_err(dev,
"Alarms can be up to one year in the future\n");
return -EINVAL;
}
}
return 0;
}
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{ {
struct cmos_rtc *cmos = dev_get_drvdata(dev); struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char mon, mday, hrs, min, sec, rtc_control; unsigned char mon, mday, hrs, min, sec, rtc_control;
int ret;
if (!is_valid_irq(cmos->irq)) if (!is_valid_irq(cmos->irq))
return -EIO; return -EIO;
ret = cmos_validate_alarm(dev, t);
if (ret < 0)
return ret;
mon = t->time.tm_mon + 1; mon = t->time.tm_mon + 1;
mday = t->time.tm_mday; mday = t->time.tm_mday;
hrs = t->time.tm_hour; hrs = t->time.tm_hour;
@ -707,9 +779,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
spin_unlock_irq(&rtc_lock); spin_unlock_irq(&rtc_lock);
/* FIXME:
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
dev_warn(dev, "only 24-hr supported\n"); dev_warn(dev, "only 24-hr supported\n");
retval = -ENXIO; retval = -ENXIO;

View File

@ -11,6 +11,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/acpi.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
@ -191,6 +192,26 @@ static const struct i2c_device_id ds1307_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, ds1307_id); MODULE_DEVICE_TABLE(i2c, ds1307_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id ds1307_acpi_ids[] = {
{ .id = "DS1307", .driver_data = ds_1307 },
{ .id = "DS1337", .driver_data = ds_1337 },
{ .id = "DS1338", .driver_data = ds_1338 },
{ .id = "DS1339", .driver_data = ds_1339 },
{ .id = "DS1388", .driver_data = ds_1388 },
{ .id = "DS1340", .driver_data = ds_1340 },
{ .id = "DS3231", .driver_data = ds_3231 },
{ .id = "M41T00", .driver_data = m41t00 },
{ .id = "MCP7940X", .driver_data = mcp794xx },
{ .id = "MCP7941X", .driver_data = mcp794xx },
{ .id = "PT7C4338", .driver_data = ds_1307 },
{ .id = "RX8025", .driver_data = rx_8025 },
{ .id = "ISL12057", .driver_data = ds_1337 },
{ }
};
MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
#endif
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
#define BLOCK_DATA_MAX_TRIES 10 #define BLOCK_DATA_MAX_TRIES 10
@ -874,17 +895,17 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client,
return setup; return setup;
} }
static void ds1307_trickle_of_init(struct i2c_client *client, static void ds1307_trickle_init(struct i2c_client *client,
struct chip_desc *chip) struct chip_desc *chip)
{ {
uint32_t ohms = 0; uint32_t ohms = 0;
bool diode = true; bool diode = true;
if (!chip->do_trickle_setup) if (!chip->do_trickle_setup)
goto out; goto out;
if (of_property_read_u32(client->dev.of_node, "trickle-resistor-ohms" , &ohms)) if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms))
goto out; goto out;
if (of_property_read_bool(client->dev.of_node, "trickle-diode-disable")) if (device_property_read_bool(&client->dev, "trickle-diode-disable"))
diode = false; diode = false;
chip->trickle_charger_setup = chip->do_trickle_setup(client, chip->trickle_charger_setup = chip->do_trickle_setup(client,
ohms, diode); ohms, diode);
@ -1268,7 +1289,7 @@ static int ds1307_probe(struct i2c_client *client,
struct ds1307 *ds1307; struct ds1307 *ds1307;
int err = -ENODEV; int err = -ENODEV;
int tmp, wday; int tmp, wday;
struct chip_desc *chip = &chips[id->driver_data]; struct chip_desc *chip;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
bool want_irq = false; bool want_irq = false;
bool ds1307_can_wakeup_device = false; bool ds1307_can_wakeup_device = false;
@ -1297,11 +1318,23 @@ static int ds1307_probe(struct i2c_client *client,
i2c_set_clientdata(client, ds1307); i2c_set_clientdata(client, ds1307);
ds1307->client = client; ds1307->client = client;
ds1307->type = id->driver_data; if (id) {
chip = &chips[id->driver_data];
ds1307->type = id->driver_data;
} else {
const struct acpi_device_id *acpi_id;
if (!pdata && client->dev.of_node) acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids),
ds1307_trickle_of_init(client, chip); &client->dev);
else if (pdata && pdata->trickle_charger_setup) if (!acpi_id)
return -ENODEV;
chip = &chips[acpi_id->driver_data];
ds1307->type = acpi_id->driver_data;
}
if (!pdata)
ds1307_trickle_init(client, chip);
else if (pdata->trickle_charger_setup)
chip->trickle_charger_setup = pdata->trickle_charger_setup; chip->trickle_charger_setup = pdata->trickle_charger_setup;
if (chip->trickle_charger_setup && chip->trickle_charger_reg) { if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
@ -1678,6 +1711,7 @@ static int ds1307_remove(struct i2c_client *client)
static struct i2c_driver ds1307_driver = { static struct i2c_driver ds1307_driver = {
.driver = { .driver = {
.name = "rtc-ds1307", .name = "rtc-ds1307",
.acpi_match_table = ACPI_PTR(ds1307_acpi_ids),
}, },
.probe = ds1307_probe, .probe = ds1307_probe,
.remove = ds1307_remove, .remove = ds1307_remove,

View File

@ -89,10 +89,8 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
int ret; int ret;
int i; int i;
if (nbytes > 4) { if (WARN_ON(nbytes > 4))
WARN_ON(1);
return -EINVAL; return -EINVAL;
}
ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf); ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf);

View File

@ -67,7 +67,7 @@
#define DSR_ETAD (1 << 21) /* External tamper A detected */ #define DSR_ETAD (1 << 21) /* External tamper A detected */
#define DSR_EBD (1 << 20) /* External boot detected */ #define DSR_EBD (1 << 20) /* External boot detected */
#define DSR_SAD (1 << 19) /* SCC alarm detected */ #define DSR_SAD (1 << 19) /* SCC alarm detected */
#define DSR_TTD (1 << 18) /* Temperatur tamper detected */ #define DSR_TTD (1 << 18) /* Temperature tamper detected */
#define DSR_CTD (1 << 17) /* Clock tamper detected */ #define DSR_CTD (1 << 17) /* Clock tamper detected */
#define DSR_VTD (1 << 16) /* Voltage tamper detected */ #define DSR_VTD (1 << 16) /* Voltage tamper detected */
#define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */ #define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */

View File

@ -14,10 +14,12 @@
* *
*/ */
#include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -27,8 +29,14 @@
#define JZ_REG_RTC_SEC_ALARM 0x08 #define JZ_REG_RTC_SEC_ALARM 0x08
#define JZ_REG_RTC_REGULATOR 0x0C #define JZ_REG_RTC_REGULATOR 0x0C
#define JZ_REG_RTC_HIBERNATE 0x20 #define JZ_REG_RTC_HIBERNATE 0x20
#define JZ_REG_RTC_WAKEUP_FILTER 0x24
#define JZ_REG_RTC_RESET_COUNTER 0x28
#define JZ_REG_RTC_SCRATCHPAD 0x34 #define JZ_REG_RTC_SCRATCHPAD 0x34
/* The following are present on the jz4780 */
#define JZ_REG_RTC_WENR 0x3C
#define JZ_RTC_WENR_WEN BIT(31)
#define JZ_RTC_CTRL_WRDY BIT(7) #define JZ_RTC_CTRL_WRDY BIT(7)
#define JZ_RTC_CTRL_1HZ BIT(6) #define JZ_RTC_CTRL_1HZ BIT(6)
#define JZ_RTC_CTRL_1HZ_IRQ BIT(5) #define JZ_RTC_CTRL_1HZ_IRQ BIT(5)
@ -37,16 +45,34 @@
#define JZ_RTC_CTRL_AE BIT(2) #define JZ_RTC_CTRL_AE BIT(2)
#define JZ_RTC_CTRL_ENABLE BIT(0) #define JZ_RTC_CTRL_ENABLE BIT(0)
/* Magic value to enable writes on jz4780 */
#define JZ_RTC_WENR_MAGIC 0xA55A
#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0
enum jz4740_rtc_type {
ID_JZ4740,
ID_JZ4780,
};
struct jz4740_rtc { struct jz4740_rtc {
void __iomem *base; void __iomem *base;
enum jz4740_rtc_type type;
struct rtc_device *rtc; struct rtc_device *rtc;
struct clk *clk;
int irq; int irq;
spinlock_t lock; spinlock_t lock;
unsigned int min_wakeup_pin_assert_time;
unsigned int reset_pin_assert_time;
}; };
static struct device *dev_for_power_off;
static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg) static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
{ {
return readl(rtc->base + reg); return readl(rtc->base + reg);
@ -64,11 +90,33 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
return timeout ? 0 : -EIO; return timeout ? 0 : -EIO;
} }
static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
int ret, timeout = 1000;
ret = jz4740_rtc_wait_write_ready(rtc);
if (ret != 0)
return ret;
writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR);
do {
ctrl = readl(rtc->base + JZ_REG_RTC_WENR);
} while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
return timeout ? 0 : -EIO;
}
static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg, static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
uint32_t val) uint32_t val)
{ {
int ret; int ret = 0;
ret = jz4740_rtc_wait_write_ready(rtc);
if (rtc->type >= ID_JZ4780)
ret = jz4780_rtc_enable_write(rtc);
if (ret == 0)
ret = jz4740_rtc_wait_write_ready(rtc);
if (ret == 0) if (ret == 0)
writel(val, rtc->base + reg); writel(val, rtc->base + reg);
@ -203,12 +251,57 @@ static irqreturn_t jz4740_rtc_irq(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
void jz4740_rtc_poweroff(struct device *dev) static void jz4740_rtc_poweroff(struct device *dev)
{ {
struct jz4740_rtc *rtc = dev_get_drvdata(dev); struct jz4740_rtc *rtc = dev_get_drvdata(dev);
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1); jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1);
} }
EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff);
static void jz4740_rtc_power_off(void)
{
struct jz4740_rtc *rtc = dev_get_drvdata(dev_for_power_off);
unsigned long rtc_rate;
unsigned long wakeup_filter_ticks;
unsigned long reset_counter_ticks;
clk_prepare_enable(rtc->clk);
rtc_rate = clk_get_rate(rtc->clk);
/*
* Set minimum wakeup pin assertion time: 100 ms.
* Range is 0 to 2 sec if RTC is clocked at 32 kHz.
*/
wakeup_filter_ticks =
(rtc->min_wakeup_pin_assert_time * rtc_rate) / 1000;
if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK)
wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK;
else
wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK;
jz4740_rtc_reg_write(rtc,
JZ_REG_RTC_WAKEUP_FILTER, wakeup_filter_ticks);
/*
* Set reset pin low-level assertion time after wakeup: 60 ms.
* Range is 0 to 125 ms if RTC is clocked at 32 kHz.
*/
reset_counter_ticks = (rtc->reset_pin_assert_time * rtc_rate) / 1000;
if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK)
reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK;
else
reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK;
jz4740_rtc_reg_write(rtc,
JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks);
jz4740_rtc_poweroff(dev_for_power_off);
machine_halt();
}
static const struct of_device_id jz4740_rtc_of_match[] = {
{ .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
{ .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
{},
};
static int jz4740_rtc_probe(struct platform_device *pdev) static int jz4740_rtc_probe(struct platform_device *pdev)
{ {
@ -216,11 +309,20 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
struct jz4740_rtc *rtc; struct jz4740_rtc *rtc;
uint32_t scratchpad; uint32_t scratchpad;
struct resource *mem; struct resource *mem;
const struct platform_device_id *id = platform_get_device_id(pdev);
const struct of_device_id *of_id = of_match_device(
jz4740_rtc_of_match, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc) if (!rtc)
return -ENOMEM; return -ENOMEM;
if (of_id)
rtc->type = (enum jz4740_rtc_type)of_id->data;
else
rtc->type = id->driver_data;
rtc->irq = platform_get_irq(pdev, 0); rtc->irq = platform_get_irq(pdev, 0);
if (rtc->irq < 0) { if (rtc->irq < 0) {
dev_err(&pdev->dev, "Failed to get platform irq\n"); dev_err(&pdev->dev, "Failed to get platform irq\n");
@ -232,6 +334,12 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
if (IS_ERR(rtc->base)) if (IS_ERR(rtc->base))
return PTR_ERR(rtc->base); return PTR_ERR(rtc->base);
rtc->clk = devm_clk_get(&pdev->dev, "rtc");
if (IS_ERR(rtc->clk)) {
dev_err(&pdev->dev, "Failed to get RTC clock\n");
return PTR_ERR(rtc->clk);
}
spin_lock_init(&rtc->lock); spin_lock_init(&rtc->lock);
platform_set_drvdata(pdev, rtc); platform_set_drvdata(pdev, rtc);
@ -263,6 +371,27 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
} }
} }
if (np && of_device_is_system_power_controller(np)) {
if (!pm_power_off) {
/* Default: 60ms */
rtc->reset_pin_assert_time = 60;
of_property_read_u32(np, "reset-pin-assert-time-ms",
&rtc->reset_pin_assert_time);
/* Default: 100ms */
rtc->min_wakeup_pin_assert_time = 100;
of_property_read_u32(np,
"min-wakeup-pin-assert-time-ms",
&rtc->min_wakeup_pin_assert_time);
dev_for_power_off = &pdev->dev;
pm_power_off = jz4740_rtc_power_off;
} else {
dev_warn(&pdev->dev,
"Poweroff handler already present!\n");
}
}
return 0; return 0;
} }
@ -295,17 +424,20 @@ static const struct dev_pm_ops jz4740_pm_ops = {
#define JZ4740_RTC_PM_OPS NULL #define JZ4740_RTC_PM_OPS NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static const struct platform_device_id jz4740_rtc_ids[] = {
{ "jz4740-rtc", ID_JZ4740 },
{ "jz4780-rtc", ID_JZ4780 },
{}
};
static struct platform_driver jz4740_rtc_driver = { static struct platform_driver jz4740_rtc_driver = {
.probe = jz4740_rtc_probe, .probe = jz4740_rtc_probe,
.driver = { .driver = {
.name = "jz4740-rtc", .name = "jz4740-rtc",
.pm = JZ4740_RTC_PM_OPS, .pm = JZ4740_RTC_PM_OPS,
.of_match_table = of_match_ptr(jz4740_rtc_of_match),
}, },
.id_table = jz4740_rtc_ids,
}; };
module_platform_driver(jz4740_rtc_driver); builtin_platform_driver(jz4740_rtc_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
MODULE_ALIAS("platform:jz4740-rtc");

View File

@ -11,7 +11,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/module.h> #include <linux/export.h>
#include <linux/rtc.h> #include <linux/rtc.h>
static const unsigned char rtc_days_in_month[] = { static const unsigned char rtc_days_in_month[] = {
@ -148,5 +148,3 @@ struct rtc_time rtc_ktime_to_tm(ktime_t kt)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(rtc_ktime_to_tm); EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
MODULE_LICENSE("GPL");

View File

@ -12,7 +12,7 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* */ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
@ -21,6 +21,8 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/bcd.h>
#include <linux/delay.h>
/* MCP795 Instructions, see datasheet table 3-1 */ /* MCP795 Instructions, see datasheet table 3-1 */
#define MCP795_EEREAD 0x03 #define MCP795_EEREAD 0x03
@ -29,7 +31,7 @@
#define MCP795_EEWREN 0x06 #define MCP795_EEWREN 0x06
#define MCP795_SRREAD 0x05 #define MCP795_SRREAD 0x05
#define MCP795_SRWRITE 0x01 #define MCP795_SRWRITE 0x01
#define MCP795_READ 0x13 #define MCP795_READ 0x13
#define MCP795_WRITE 0x12 #define MCP795_WRITE 0x12
#define MCP795_UNLOCK 0x14 #define MCP795_UNLOCK 0x14
#define MCP795_IDWRITE 0x32 #define MCP795_IDWRITE 0x32
@ -37,8 +39,17 @@
#define MCP795_CLRWDT 0x44 #define MCP795_CLRWDT 0x44
#define MCP795_CLRRAM 0x54 #define MCP795_CLRRAM 0x54
#define MCP795_ST_BIT 0x80 /* MCP795 RTCC registers, see datasheet table 4-1 */
#define MCP795_24_BIT 0x40 #define MCP795_REG_SECONDS 0x01
#define MCP795_REG_DAY 0x04
#define MCP795_REG_MONTH 0x06
#define MCP795_REG_CONTROL 0x08
#define MCP795_ST_BIT BIT(7)
#define MCP795_24_BIT BIT(6)
#define MCP795_LP_BIT BIT(5)
#define MCP795_EXTOSC_BIT BIT(3)
#define MCP795_OSCON_BIT BIT(5)
static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count) static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count)
{ {
@ -93,30 +104,97 @@ static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state)
return ret; return ret;
} }
static int mcp795_stop_oscillator(struct device *dev, bool *extosc)
{
int retries = 5;
int ret;
u8 data;
ret = mcp795_rtcc_set_bits(dev, MCP795_REG_SECONDS, MCP795_ST_BIT, 0);
if (ret)
return ret;
ret = mcp795_rtcc_read(dev, MCP795_REG_CONTROL, &data, 1);
if (ret)
return ret;
*extosc = !!(data & MCP795_EXTOSC_BIT);
ret = mcp795_rtcc_set_bits(
dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, 0);
if (ret)
return ret;
/* wait for the OSCON bit to clear */
do {
usleep_range(700, 800);
ret = mcp795_rtcc_read(dev, MCP795_REG_DAY, &data, 1);
if (ret)
break;
if (!(data & MCP795_OSCON_BIT))
break;
} while (--retries);
return !retries ? -EIO : ret;
}
static int mcp795_start_oscillator(struct device *dev, bool *extosc)
{
if (extosc) {
u8 data = *extosc ? MCP795_EXTOSC_BIT : 0;
int ret;
ret = mcp795_rtcc_set_bits(
dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, data);
if (ret)
return ret;
}
return mcp795_rtcc_set_bits(
dev, MCP795_REG_SECONDS, MCP795_ST_BIT, MCP795_ST_BIT);
}
static int mcp795_set_time(struct device *dev, struct rtc_time *tim) static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
{ {
int ret; int ret;
u8 data[7]; u8 data[7];
bool extosc;
/* Stop RTC and store current value of EXTOSC bit */
ret = mcp795_stop_oscillator(dev, &extosc);
if (ret)
return ret;
/* Read first, so we can leave config bits untouched */ /* Read first, so we can leave config bits untouched */
ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
if (ret) if (ret)
return ret; return ret;
data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10); data[0] = (data[0] & 0x80) | bin2bcd(tim->tm_sec);
data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10); data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min);
data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10); data[2] = bin2bcd(tim->tm_hour);
data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10); data[4] = bin2bcd(tim->tm_mday);
data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10); data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon + 1);
if (tim->tm_year > 100) if (tim->tm_year > 100)
tim->tm_year -= 100; tim->tm_year -= 100;
data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10); data[6] = bin2bcd(tim->tm_year);
ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data)); /* Always write the date and month using a separate Write command.
* This is a workaround for a know silicon issue that some combinations
* of date and month values may result in the date being reset to 1.
*/
ret = mcp795_rtcc_write(dev, MCP795_REG_SECONDS, data, 5);
if (ret)
return ret;
ret = mcp795_rtcc_write(dev, MCP795_REG_MONTH, &data[5], 2);
if (ret)
return ret;
/* Start back RTC and restore previous value of EXTOSC bit.
* There is no need to clear EXTOSC bit when the previous value was 0
* because it was already cleared when stopping the RTC oscillator.
*/
ret = mcp795_start_oscillator(dev, extosc ? &extosc : NULL);
if (ret) if (ret)
return ret; return ret;
@ -132,17 +210,17 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim)
int ret; int ret;
u8 data[7]; u8 data[7];
ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data));
if (ret) if (ret)
return ret; return ret;
tim->tm_sec = ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f); tim->tm_sec = bcd2bin(data[0] & 0x7F);
tim->tm_min = ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f); tim->tm_min = bcd2bin(data[1] & 0x7F);
tim->tm_hour = ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f); tim->tm_hour = bcd2bin(data[2] & 0x3F);
tim->tm_mday = ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f); tim->tm_mday = bcd2bin(data[4] & 0x3F);
tim->tm_mon = ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f); tim->tm_mon = bcd2bin(data[5] & 0x1F) - 1;
tim->tm_year = ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */ tim->tm_year = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */
dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
@ -169,13 +247,13 @@ static int mcp795_probe(struct spi_device *spi)
return ret; return ret;
} }
/* Start the oscillator */ /* Start the oscillator but don't set the value of EXTOSC bit */
mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT); mcp795_start_oscillator(&spi->dev, NULL);
/* Clear the 12 hour mode flag*/ /* Clear the 12 hour mode flag*/
mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0); mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0);
rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795", rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795",
&mcp795_rtc_ops, THIS_MODULE); &mcp795_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) if (IS_ERR(rtc))
return PTR_ERR(rtc); return PTR_ERR(rtc);

View File

@ -191,12 +191,19 @@ static int pcf85063_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct rtc_device *rtc; struct rtc_device *rtc;
int err;
dev_dbg(&client->dev, "%s\n", __func__); dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV; return -ENODEV;
err = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
if (err < 0) {
dev_err(&client->dev, "RTC chip is not present\n");
return err;
}
rtc = devm_rtc_device_register(&client->dev, rtc = devm_rtc_device_register(&client->dev,
pcf85063_driver.driver.name, pcf85063_driver.driver.name,
&pcf85063_rtc_ops, THIS_MODULE); &pcf85063_rtc_ops, THIS_MODULE);

453
drivers/rtc/rtc-r7301.c Normal file
View File

@ -0,0 +1,453 @@
/*
* EPSON TOYOCOM RTC-7301SF/DG Driver
*
* Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
*
* Based on rtc-rp5c01.c
*
* Datasheet: http://www5.epsondevice.com/en/products/parallel/rtc7301sf.html
*/
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#define DRV_NAME "rtc-r7301"
#define RTC7301_1_SEC 0x0 /* Bank 0 and Band 1 */
#define RTC7301_10_SEC 0x1 /* Bank 0 and Band 1 */
#define RTC7301_AE BIT(3)
#define RTC7301_1_MIN 0x2 /* Bank 0 and Band 1 */
#define RTC7301_10_MIN 0x3 /* Bank 0 and Band 1 */
#define RTC7301_1_HOUR 0x4 /* Bank 0 and Band 1 */
#define RTC7301_10_HOUR 0x5 /* Bank 0 and Band 1 */
#define RTC7301_DAY_OF_WEEK 0x6 /* Bank 0 and Band 1 */
#define RTC7301_1_DAY 0x7 /* Bank 0 and Band 1 */
#define RTC7301_10_DAY 0x8 /* Bank 0 and Band 1 */
#define RTC7301_1_MONTH 0x9 /* Bank 0 */
#define RTC7301_10_MONTH 0xa /* Bank 0 */
#define RTC7301_1_YEAR 0xb /* Bank 0 */
#define RTC7301_10_YEAR 0xc /* Bank 0 */
#define RTC7301_100_YEAR 0xd /* Bank 0 */
#define RTC7301_1000_YEAR 0xe /* Bank 0 */
#define RTC7301_ALARM_CONTROL 0xe /* Bank 1 */
#define RTC7301_ALARM_CONTROL_AIE BIT(0)
#define RTC7301_ALARM_CONTROL_AF BIT(1)
#define RTC7301_TIMER_CONTROL 0xe /* Bank 2 */
#define RTC7301_TIMER_CONTROL_TIE BIT(0)
#define RTC7301_TIMER_CONTROL_TF BIT(1)
#define RTC7301_CONTROL 0xf /* All banks */
#define RTC7301_CONTROL_BUSY BIT(0)
#define RTC7301_CONTROL_STOP BIT(1)
#define RTC7301_CONTROL_BANK_SEL_0 BIT(2)
#define RTC7301_CONTROL_BANK_SEL_1 BIT(3)
struct rtc7301_priv {
struct regmap *regmap;
int irq;
spinlock_t lock;
u8 bank;
};
static const struct regmap_config rtc7301_regmap_config = {
.reg_bits = 32,
.val_bits = 8,
.reg_stride = 4,
};
static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg)
{
int reg_stride = regmap_get_reg_stride(priv->regmap);
unsigned int val;
regmap_read(priv->regmap, reg_stride * reg, &val);
return val & 0xf;
}
static void rtc7301_write(struct rtc7301_priv *priv, u8 val, unsigned int reg)
{
int reg_stride = regmap_get_reg_stride(priv->regmap);
regmap_write(priv->regmap, reg_stride * reg, val);
}
static void rtc7301_update_bits(struct rtc7301_priv *priv, unsigned int reg,
u8 mask, u8 val)
{
int reg_stride = regmap_get_reg_stride(priv->regmap);
regmap_update_bits(priv->regmap, reg_stride * reg, mask, val);
}
static int rtc7301_wait_while_busy(struct rtc7301_priv *priv)
{
int retries = 100;
while (retries-- > 0) {
u8 val;
val = rtc7301_read(priv, RTC7301_CONTROL);
if (!(val & RTC7301_CONTROL_BUSY))
return 0;
usleep_range(200, 300);
}
return -ETIMEDOUT;
}
static void rtc7301_stop(struct rtc7301_priv *priv)
{
rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP,
RTC7301_CONTROL_STOP);
}
static void rtc7301_start(struct rtc7301_priv *priv)
{
rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, 0);
}
static void rtc7301_select_bank(struct rtc7301_priv *priv, u8 bank)
{
u8 val = 0;
if (bank == priv->bank)
return;
if (bank & BIT(0))
val |= RTC7301_CONTROL_BANK_SEL_0;
if (bank & BIT(1))
val |= RTC7301_CONTROL_BANK_SEL_1;
rtc7301_update_bits(priv, RTC7301_CONTROL,
RTC7301_CONTROL_BANK_SEL_0 |
RTC7301_CONTROL_BANK_SEL_1, val);
priv->bank = bank;
}
static void rtc7301_get_time(struct rtc7301_priv *priv, struct rtc_time *tm,
bool alarm)
{
int year;
tm->tm_sec = rtc7301_read(priv, RTC7301_1_SEC);
tm->tm_sec += (rtc7301_read(priv, RTC7301_10_SEC) & ~RTC7301_AE) * 10;
tm->tm_min = rtc7301_read(priv, RTC7301_1_MIN);
tm->tm_min += (rtc7301_read(priv, RTC7301_10_MIN) & ~RTC7301_AE) * 10;
tm->tm_hour = rtc7301_read(priv, RTC7301_1_HOUR);
tm->tm_hour += (rtc7301_read(priv, RTC7301_10_HOUR) & ~RTC7301_AE) * 10;
tm->tm_mday = rtc7301_read(priv, RTC7301_1_DAY);
tm->tm_mday += (rtc7301_read(priv, RTC7301_10_DAY) & ~RTC7301_AE) * 10;
if (alarm) {
tm->tm_wday = -1;
tm->tm_mon = -1;
tm->tm_year = -1;
tm->tm_yday = -1;
tm->tm_isdst = -1;
return;
}
tm->tm_wday = (rtc7301_read(priv, RTC7301_DAY_OF_WEEK) & ~RTC7301_AE);
tm->tm_mon = rtc7301_read(priv, RTC7301_10_MONTH) * 10 +
rtc7301_read(priv, RTC7301_1_MONTH) - 1;
year = rtc7301_read(priv, RTC7301_1000_YEAR) * 1000 +
rtc7301_read(priv, RTC7301_100_YEAR) * 100 +
rtc7301_read(priv, RTC7301_10_YEAR) * 10 +
rtc7301_read(priv, RTC7301_1_YEAR);
tm->tm_year = year - 1900;
}
static void rtc7301_write_time(struct rtc7301_priv *priv, struct rtc_time *tm,
bool alarm)
{
int year;
rtc7301_write(priv, tm->tm_sec % 10, RTC7301_1_SEC);
rtc7301_write(priv, tm->tm_sec / 10, RTC7301_10_SEC);
rtc7301_write(priv, tm->tm_min % 10, RTC7301_1_MIN);
rtc7301_write(priv, tm->tm_min / 10, RTC7301_10_MIN);
rtc7301_write(priv, tm->tm_hour % 10, RTC7301_1_HOUR);
rtc7301_write(priv, tm->tm_hour / 10, RTC7301_10_HOUR);
rtc7301_write(priv, tm->tm_mday % 10, RTC7301_1_DAY);
rtc7301_write(priv, tm->tm_mday / 10, RTC7301_10_DAY);
/* Don't care for alarm register */
rtc7301_write(priv, alarm ? RTC7301_AE : tm->tm_wday,
RTC7301_DAY_OF_WEEK);
if (alarm)
return;
rtc7301_write(priv, (tm->tm_mon + 1) % 10, RTC7301_1_MONTH);
rtc7301_write(priv, (tm->tm_mon + 1) / 10, RTC7301_10_MONTH);
year = tm->tm_year + 1900;
rtc7301_write(priv, year % 10, RTC7301_1_YEAR);
rtc7301_write(priv, (year / 10) % 10, RTC7301_10_YEAR);
rtc7301_write(priv, (year / 100) % 10, RTC7301_100_YEAR);
rtc7301_write(priv, year / 1000, RTC7301_1000_YEAR);
}
static void rtc7301_alarm_irq(struct rtc7301_priv *priv, unsigned int enabled)
{
rtc7301_update_bits(priv, RTC7301_ALARM_CONTROL,
RTC7301_ALARM_CONTROL_AF |
RTC7301_ALARM_CONTROL_AIE,
enabled ? RTC7301_ALARM_CONTROL_AIE : 0);
}
static int rtc7301_read_time(struct device *dev, struct rtc_time *tm)
{
struct rtc7301_priv *priv = dev_get_drvdata(dev);
unsigned long flags;
int err;
spin_lock_irqsave(&priv->lock, flags);
rtc7301_select_bank(priv, 0);
err = rtc7301_wait_while_busy(priv);
if (!err)
rtc7301_get_time(priv, tm, false);
spin_unlock_irqrestore(&priv->lock, flags);
return err ? err : rtc_valid_tm(tm);
}
static int rtc7301_set_time(struct device *dev, struct rtc_time *tm)
{
struct rtc7301_priv *priv = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
rtc7301_stop(priv);
usleep_range(200, 300);
rtc7301_select_bank(priv, 0);
rtc7301_write_time(priv, tm, false);
rtc7301_start(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static int rtc7301_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct rtc7301_priv *priv = dev_get_drvdata(dev);
unsigned long flags;
u8 alrm_ctrl;
if (priv->irq <= 0)
return -EINVAL;
spin_lock_irqsave(&priv->lock, flags);
rtc7301_select_bank(priv, 1);
rtc7301_get_time(priv, &alarm->time, true);
alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
alarm->enabled = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AIE);
alarm->pending = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AF);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static int rtc7301_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct rtc7301_priv *priv = dev_get_drvdata(dev);
unsigned long flags;
if (priv->irq <= 0)
return -EINVAL;
spin_lock_irqsave(&priv->lock, flags);
rtc7301_select_bank(priv, 1);
rtc7301_write_time(priv, &alarm->time, true);
rtc7301_alarm_irq(priv, alarm->enabled);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static int rtc7301_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct rtc7301_priv *priv = dev_get_drvdata(dev);
unsigned long flags;
if (priv->irq <= 0)
return -EINVAL;
spin_lock_irqsave(&priv->lock, flags);
rtc7301_select_bank(priv, 1);
rtc7301_alarm_irq(priv, enabled);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static const struct rtc_class_ops rtc7301_rtc_ops = {
.read_time = rtc7301_read_time,
.set_time = rtc7301_set_time,
.read_alarm = rtc7301_read_alarm,
.set_alarm = rtc7301_set_alarm,
.alarm_irq_enable = rtc7301_alarm_irq_enable,
};
static irqreturn_t rtc7301_irq_handler(int irq, void *dev_id)
{
struct rtc_device *rtc = dev_id;
struct rtc7301_priv *priv = dev_get_drvdata(rtc->dev.parent);
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
u8 alrm_ctrl;
spin_lock_irqsave(&priv->lock, flags);
rtc7301_select_bank(priv, 1);
alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL);
if (alrm_ctrl & RTC7301_ALARM_CONTROL_AF) {
ret = IRQ_HANDLED;
rtc7301_alarm_irq(priv, false);
rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
}
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
static void rtc7301_init(struct rtc7301_priv *priv)
{
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
rtc7301_select_bank(priv, 2);
rtc7301_write(priv, 0, RTC7301_TIMER_CONTROL);
spin_unlock_irqrestore(&priv->lock, flags);
}
static int __init rtc7301_rtc_probe(struct platform_device *dev)
{
struct resource *res;
void __iomem *regs;
struct rtc7301_priv *priv;
struct rtc_device *rtc;
int ret;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
regs = devm_ioremap_resource(&dev->dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
priv->regmap = devm_regmap_init_mmio(&dev->dev, regs,
&rtc7301_regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
priv->irq = platform_get_irq(dev, 0);
spin_lock_init(&priv->lock);
priv->bank = -1;
rtc7301_init(priv);
platform_set_drvdata(dev, priv);
rtc = devm_rtc_device_register(&dev->dev, DRV_NAME, &rtc7301_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
if (priv->irq > 0) {
ret = devm_request_irq(&dev->dev, priv->irq,
rtc7301_irq_handler, IRQF_SHARED,
dev_name(&dev->dev), rtc);
if (ret) {
priv->irq = 0;
dev_err(&dev->dev, "unable to request IRQ\n");
} else {
device_set_wakeup_capable(&dev->dev, true);
}
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rtc7301_suspend(struct device *dev)
{
struct rtc7301_priv *priv = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(priv->irq);
return 0;
}
static int rtc7301_resume(struct device *dev)
{
struct rtc7301_priv *priv = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(priv->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(rtc7301_pm_ops, rtc7301_suspend, rtc7301_resume);
static const struct of_device_id rtc7301_dt_match[] = {
{ .compatible = "epson,rtc7301sf" },
{ .compatible = "epson,rtc7301dg" },
{}
};
MODULE_DEVICE_TABLE(of, rtc7301_dt_match);
static struct platform_driver rtc7301_rtc_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = rtc7301_dt_match,
.pm = &rtc7301_pm_ops,
},
};
module_platform_driver_probe(rtc7301_rtc_driver, rtc7301_rtc_probe);
MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EPSON TOYOCOM RTC-7301SF/DG Driver");
MODULE_ALIAS("platform:rtc-r7301");

View File

@ -1,20 +1,18 @@
/* rtc-starfire.c: Starfire platform RTC driver. /* rtc-starfire.c: Starfire platform RTC driver.
*
* Author: David S. Miller
* License: GPL
* *
* Copyright (C) 2008 David S. Miller <davem@davemloft.net> * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <asm/oplib.h> #include <asm/oplib.h>
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Starfire RTC driver");
MODULE_LICENSE("GPL");
static u32 starfire_get_time(void) static u32 starfire_get_time(void)
{ {
static char obp_gettod[32]; static char obp_gettod[32];
@ -57,4 +55,4 @@ static struct platform_driver starfire_rtc_driver = {
}, },
}; };
module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe); builtin_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);

View File

@ -1,4 +1,7 @@
/* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems. /* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems.
*
* Author: David S. Miller
* License: GPL
* *
* Copyright (C) 2008 David S. Miller <davem@davemloft.net> * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/ */
@ -6,7 +9,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/rtc.h> #include <linux/rtc.h>
@ -98,8 +100,4 @@ static struct platform_driver sun4v_rtc_driver = {
}, },
}; };
module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe); builtin_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("SUN4V RTC driver");
MODULE_LICENSE("GPL");

View File

@ -33,6 +33,10 @@
#include <linux/i2c/twl.h> #include <linux/i2c/twl.h>
enum twl_class {
TWL_4030 = 0,
TWL_6030,
};
/* /*
* RTC block register offsets (use TWL_MODULE_RTC) * RTC block register offsets (use TWL_MODULE_RTC)
@ -136,16 +140,30 @@ static const u8 twl6030_rtc_reg_map[] = {
#define ALL_TIME_REGS 6 #define ALL_TIME_REGS 6
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
static u8 *rtc_reg_map; struct twl_rtc {
struct device *dev;
struct rtc_device *rtc;
u8 *reg_map;
/*
* Cache the value for timer/alarm interrupts register; this is
* only changed by callers holding rtc ops lock (or resume).
*/
unsigned char rtc_irq_bits;
bool wake_enabled;
#ifdef CONFIG_PM_SLEEP
unsigned char irqstat;
#endif
enum twl_class class;
};
/* /*
* Supports 1 byte read from TWL RTC register. * Supports 1 byte read from TWL RTC register.
*/ */
static int twl_rtc_read_u8(u8 *data, u8 reg) static int twl_rtc_read_u8(struct twl_rtc *twl_rtc, u8 *data, u8 reg)
{ {
int ret; int ret;
ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
if (ret < 0) if (ret < 0)
pr_err("Could not read TWL register %X - error %d\n", reg, ret); pr_err("Could not read TWL register %X - error %d\n", reg, ret);
return ret; return ret;
@ -154,40 +172,34 @@ static int twl_rtc_read_u8(u8 *data, u8 reg)
/* /*
* Supports 1 byte write to TWL RTC registers. * Supports 1 byte write to TWL RTC registers.
*/ */
static int twl_rtc_write_u8(u8 data, u8 reg) static int twl_rtc_write_u8(struct twl_rtc *twl_rtc, u8 data, u8 reg)
{ {
int ret; int ret;
ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
if (ret < 0) if (ret < 0)
pr_err("Could not write TWL register %X - error %d\n", pr_err("Could not write TWL register %X - error %d\n",
reg, ret); reg, ret);
return ret; return ret;
} }
/*
* Cache the value for timer/alarm interrupts register; this is
* only changed by callers holding rtc ops lock (or resume).
*/
static unsigned char rtc_irq_bits;
/* /*
* Enable 1/second update and/or alarm interrupts. * Enable 1/second update and/or alarm interrupts.
*/ */
static int set_rtc_irq_bit(unsigned char bit) static int set_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
{ {
unsigned char val; unsigned char val;
int ret; int ret;
/* if the bit is set, return from here */ /* if the bit is set, return from here */
if (rtc_irq_bits & bit) if (twl_rtc->rtc_irq_bits & bit)
return 0; return 0;
val = rtc_irq_bits | bit; val = twl_rtc->rtc_irq_bits | bit;
val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
if (ret == 0) if (ret == 0)
rtc_irq_bits = val; twl_rtc->rtc_irq_bits = val;
return ret; return ret;
} }
@ -195,19 +207,19 @@ static int set_rtc_irq_bit(unsigned char bit)
/* /*
* Disable update and/or alarm interrupts. * Disable update and/or alarm interrupts.
*/ */
static int mask_rtc_irq_bit(unsigned char bit) static int mask_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
{ {
unsigned char val; unsigned char val;
int ret; int ret;
/* if the bit is clear, return from here */ /* if the bit is clear, return from here */
if (!(rtc_irq_bits & bit)) if (!(twl_rtc->rtc_irq_bits & bit))
return 0; return 0;
val = rtc_irq_bits & ~bit; val = twl_rtc->rtc_irq_bits & ~bit;
ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
if (ret == 0) if (ret == 0)
rtc_irq_bits = val; twl_rtc->rtc_irq_bits = val;
return ret; return ret;
} }
@ -215,21 +227,23 @@ static int mask_rtc_irq_bit(unsigned char bit)
static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
int irq = platform_get_irq(pdev, 0); int irq = platform_get_irq(pdev, 0);
static bool twl_rtc_wake_enabled;
int ret; int ret;
if (enabled) { if (enabled) {
ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); ret = set_rtc_irq_bit(twl_rtc,
if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) { BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
if (device_can_wakeup(dev) && !twl_rtc->wake_enabled) {
enable_irq_wake(irq); enable_irq_wake(irq);
twl_rtc_wake_enabled = true; twl_rtc->wake_enabled = true;
} }
} else { } else {
ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); ret = mask_rtc_irq_bit(twl_rtc,
if (twl_rtc_wake_enabled) { BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
if (twl_rtc->wake_enabled) {
disable_irq_wake(irq); disable_irq_wake(irq);
twl_rtc_wake_enabled = false; twl_rtc->wake_enabled = false;
} }
} }
@ -247,21 +261,23 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
*/ */
static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
unsigned char rtc_data[ALL_TIME_REGS]; unsigned char rtc_data[ALL_TIME_REGS];
int ret; int ret;
u8 save_control; u8 save_control;
u8 rtc_control; u8 rtc_control;
ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret); dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret);
return ret; return ret;
} }
/* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */ /* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */
if (twl_class_is_6030()) { if (twl_rtc->class == TWL_6030) {
if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) { if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) {
save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M; save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M;
ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); ret = twl_rtc_write_u8(twl_rtc, save_control,
REG_RTC_CTRL_REG);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s clr GET_TIME, error %d\n", dev_err(dev, "%s clr GET_TIME, error %d\n",
__func__, ret); __func__, ret);
@ -274,17 +290,17 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M; rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M;
/* for twl6030/32 enable read access to static shadowed registers */ /* for twl6030/32 enable read access to static shadowed registers */
if (twl_class_is_6030()) if (twl_rtc->class == TWL_6030)
rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT; rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT;
ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG); ret = twl_rtc_write_u8(twl_rtc, rtc_control, REG_RTC_CTRL_REG);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret); dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret);
return ret; return ret;
} }
ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: reading data, error %d\n", __func__, ret); dev_err(dev, "%s: reading data, error %d\n", __func__, ret);
@ -292,8 +308,8 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
} }
/* for twl6030 restore original state of rtc control register */ /* for twl6030 restore original state of rtc control register */
if (twl_class_is_6030()) { if (twl_rtc->class == TWL_6030) {
ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: restore CTRL_REG, error %d\n", dev_err(dev, "%s: restore CTRL_REG, error %d\n",
__func__, ret); __func__, ret);
@ -313,6 +329,7 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
{ {
struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
unsigned char save_control; unsigned char save_control;
unsigned char rtc_data[ALL_TIME_REGS]; unsigned char rtc_data[ALL_TIME_REGS];
int ret; int ret;
@ -325,18 +342,18 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_data[5] = bin2bcd(tm->tm_year - 100); rtc_data[5] = bin2bcd(tm->tm_year - 100);
/* Stop RTC while updating the TC registers */ /* Stop RTC while updating the TC registers */
ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
if (ret < 0) if (ret < 0)
goto out; goto out;
save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
if (ret < 0) if (ret < 0)
goto out; goto out;
/* update all the time registers in one shot */ /* update all the time registers in one shot */
ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data, ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "rtc_set_time error %d\n", ret); dev_err(dev, "rtc_set_time error %d\n", ret);
goto out; goto out;
@ -344,7 +361,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* Start back RTC */ /* Start back RTC */
save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
out: out:
return ret; return ret;
@ -355,11 +372,12 @@ out:
*/ */
static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{ {
struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
unsigned char rtc_data[ALL_TIME_REGS]; unsigned char rtc_data[ALL_TIME_REGS];
int ret; int ret;
ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "rtc_read_alarm error %d\n", ret); dev_err(dev, "rtc_read_alarm error %d\n", ret);
return ret; return ret;
@ -374,7 +392,7 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
alm->time.tm_year = bcd2bin(rtc_data[5]) + 100; alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
/* report cached alarm enable state */ /* report cached alarm enable state */
if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) if (twl_rtc->rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
alm->enabled = 1; alm->enabled = 1;
return ret; return ret;
@ -382,6 +400,8 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{ {
struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
unsigned char alarm_data[ALL_TIME_REGS]; unsigned char alarm_data[ALL_TIME_REGS];
int ret; int ret;
@ -398,7 +418,7 @@ static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
/* update all the alarm registers in one shot */ /* update all the alarm registers in one shot */
ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
if (ret) { if (ret) {
dev_err(dev, "rtc_set_alarm error %d\n", ret); dev_err(dev, "rtc_set_alarm error %d\n", ret);
goto out; goto out;
@ -410,14 +430,15 @@ out:
return ret; return ret;
} }
static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) static irqreturn_t twl_rtc_interrupt(int irq, void *data)
{ {
struct twl_rtc *twl_rtc = data;
unsigned long events; unsigned long events;
int ret = IRQ_NONE; int ret = IRQ_NONE;
int res; int res;
u8 rd_reg; u8 rd_reg;
res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); res = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
if (res) if (res)
goto out; goto out;
/* /*
@ -431,12 +452,12 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
else else
events = RTC_IRQF | RTC_PF; events = RTC_IRQF | RTC_PF;
res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M, res = twl_rtc_write_u8(twl_rtc, BIT_RTC_STATUS_REG_ALARM_M,
REG_RTC_STATUS_REG); REG_RTC_STATUS_REG);
if (res) if (res)
goto out; goto out;
if (twl_class_is_4030()) { if (twl_rtc->class == TWL_4030) {
/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
* needs 2 reads to clear the interrupt. One read is done in * needs 2 reads to clear the interrupt. One read is done in
* do_twl_pwrirq(). Doing the second read, to clear * do_twl_pwrirq(). Doing the second read, to clear
@ -455,7 +476,7 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
} }
/* Notify RTC core on event */ /* Notify RTC core on event */
rtc_update_irq(rtc, 1, events); rtc_update_irq(twl_rtc->rtc, 1, events);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
out: out:
@ -474,21 +495,36 @@ static const struct rtc_class_ops twl_rtc_ops = {
static int twl_rtc_probe(struct platform_device *pdev) static int twl_rtc_probe(struct platform_device *pdev)
{ {
struct rtc_device *rtc; struct twl_rtc *twl_rtc;
struct device_node *np = pdev->dev.of_node;
int ret = -EINVAL; int ret = -EINVAL;
int irq = platform_get_irq(pdev, 0); int irq = platform_get_irq(pdev, 0);
u8 rd_reg; u8 rd_reg;
if (!np) {
dev_err(&pdev->dev, "no DT info\n");
return -EINVAL;
}
if (irq <= 0) if (irq <= 0)
return ret; return ret;
/* Initialize the register map */ twl_rtc = devm_kzalloc(&pdev->dev, sizeof(*twl_rtc), GFP_KERNEL);
if (twl_class_is_4030()) if (!twl_rtc)
rtc_reg_map = (u8 *)twl4030_rtc_reg_map; return -ENOMEM;
else
rtc_reg_map = (u8 *)twl6030_rtc_reg_map;
ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); if (twl_class_is_4030()) {
twl_rtc->class = TWL_4030;
twl_rtc->reg_map = (u8 *)twl4030_rtc_reg_map;
} else if (twl_class_is_6030()) {
twl_rtc->class = TWL_6030;
twl_rtc->reg_map = (u8 *)twl6030_rtc_reg_map;
} else {
dev_err(&pdev->dev, "TWL Class not supported.\n");
return -EINVAL;
}
ret = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -499,11 +535,11 @@ static int twl_rtc_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
/* Clear RTC Power up reset and pending alarm interrupts */ /* Clear RTC Power up reset and pending alarm interrupts */
ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); ret = twl_rtc_write_u8(twl_rtc, rd_reg, REG_RTC_STATUS_REG);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (twl_class_is_6030()) { if (twl_rtc->class == TWL_6030) {
twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_LINE_A); REG_INT_MSK_LINE_A);
twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
@ -511,40 +547,42 @@ static int twl_rtc_probe(struct platform_device *pdev)
} }
dev_info(&pdev->dev, "Enabling TWL-RTC\n"); dev_info(&pdev->dev, "Enabling TWL-RTC\n");
ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG); ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
REG_RTC_CTRL_REG);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* ensure interrupts are disabled, bootloaders can be strange */ /* ensure interrupts are disabled, bootloaders can be strange */
ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); ret = twl_rtc_write_u8(twl_rtc, 0, REG_RTC_INTERRUPTS_REG);
if (ret < 0) if (ret < 0)
dev_warn(&pdev->dev, "unable to disable interrupt\n"); dev_warn(&pdev->dev, "unable to disable interrupt\n");
/* init cached IRQ enable bits */ /* init cached IRQ enable bits */
ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); ret = twl_rtc_read_u8(twl_rtc, &twl_rtc->rtc_irq_bits,
REG_RTC_INTERRUPTS_REG);
if (ret < 0) if (ret < 0)
return ret; return ret;
platform_set_drvdata(pdev, twl_rtc);
device_init_wakeup(&pdev->dev, 1); device_init_wakeup(&pdev->dev, 1);
rtc = devm_rtc_device_register(&pdev->dev, pdev->name, twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&twl_rtc_ops, THIS_MODULE); &twl_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) { if (IS_ERR(twl_rtc->rtc)) {
dev_err(&pdev->dev, "can't register RTC device, err %ld\n", dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(rtc)); PTR_ERR(twl_rtc->rtc));
return PTR_ERR(rtc); return PTR_ERR(twl_rtc->rtc);
} }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl_rtc_interrupt, twl_rtc_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(&rtc->dev), rtc); dev_name(&twl_rtc->rtc->dev), twl_rtc);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "IRQ is not free.\n"); dev_err(&pdev->dev, "IRQ is not free.\n");
return ret; return ret;
} }
platform_set_drvdata(pdev, rtc);
return 0; return 0;
} }
@ -554,10 +592,12 @@ static int twl_rtc_probe(struct platform_device *pdev)
*/ */
static int twl_rtc_remove(struct platform_device *pdev) static int twl_rtc_remove(struct platform_device *pdev)
{ {
struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
/* leave rtc running, but disable irqs */ /* leave rtc running, but disable irqs */
mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
if (twl_class_is_6030()) { if (twl_rtc->class == TWL_6030) {
twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_LINE_A); REG_INT_MSK_LINE_A);
twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
@ -569,40 +609,40 @@ static int twl_rtc_remove(struct platform_device *pdev)
static void twl_rtc_shutdown(struct platform_device *pdev) static void twl_rtc_shutdown(struct platform_device *pdev)
{ {
struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
/* mask timer interrupts, but leave alarm interrupts on to enable /* mask timer interrupts, but leave alarm interrupts on to enable
power-on when alarm is triggered */ power-on when alarm is triggered */
mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static unsigned char irqstat;
static int twl_rtc_suspend(struct device *dev) static int twl_rtc_suspend(struct device *dev)
{ {
irqstat = rtc_irq_bits; struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); twl_rtc->irqstat = twl_rtc->rtc_irq_bits;
mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
return 0; return 0;
} }
static int twl_rtc_resume(struct device *dev) static int twl_rtc_resume(struct device *dev)
{ {
set_rtc_irq_bit(irqstat); struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
set_rtc_irq_bit(twl_rtc, twl_rtc->irqstat);
return 0; return 0;
} }
#endif #endif
static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume); static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume);
#ifdef CONFIG_OF
static const struct of_device_id twl_rtc_of_match[] = { static const struct of_device_id twl_rtc_of_match[] = {
{.compatible = "ti,twl4030-rtc", }, {.compatible = "ti,twl4030-rtc", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, twl_rtc_of_match); MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
#endif
MODULE_ALIAS("platform:twl_rtc");
static struct platform_driver twl4030rtc_driver = { static struct platform_driver twl4030rtc_driver = {
.probe = twl_rtc_probe, .probe = twl_rtc_probe,
@ -611,7 +651,7 @@ static struct platform_driver twl4030rtc_driver = {
.driver = { .driver = {
.name = "twl_rtc", .name = "twl_rtc",
.pm = &twl_rtc_pm_ops, .pm = &twl_rtc_pm_ops,
.of_match_table = of_match_ptr(twl_rtc_of_match), .of_match_table = twl_rtc_of_match,
}, },
}; };