Commit b0b3a37b authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 3be134e5 d3e59259
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.
......
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>;
};
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>;
};
* 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:
rtc@0 { Example:
rtc {
compatible = "ti,twl4030-rtc"; compatible = "ti,twl4030-rtc";
}; interrupts = <11>;
};
...@@ -44,6 +44,17 @@ cgu: jz4740-cgu@10000000 { ...@@ -44,6 +44,17 @@ cgu: jz4740-cgu@10000000 {
#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>;
......
...@@ -13,3 +13,7 @@ chosen { ...@@ -13,3 +13,7 @@ chosen {
&ext { &ext {
clock-frequency = <12000000>; clock-frequency = <12000000>;
}; };
&rtc_dev {
system-power-controller;
};
...@@ -22,7 +22,6 @@ ...@@ -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;
......
...@@ -438,7 +438,6 @@ static struct platform_device *jz_platform_devices[] __initdata = { ...@@ -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,
......
...@@ -88,27 +88,6 @@ struct platform_device jz4740_mmc_device = { ...@@ -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[] = {
{ {
......
...@@ -57,71 +57,8 @@ static void jz4740_restart(char *command) ...@@ -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;
} }
...@@ -303,7 +303,7 @@ config RTC_DRV_MAX6900 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -120,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o ...@@ -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
......
...@@ -332,14 +332,86 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask) ...@@ -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) ...@@ -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;
......
...@@ -11,6 +11,7 @@ ...@@ -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[] = { ...@@ -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,7 +895,7 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client, ...@@ -874,7 +895,7 @@ 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;
...@@ -882,9 +903,9 @@ static void ds1307_trickle_of_init(struct i2c_client *client, ...@@ -882,9 +903,9 @@ static void ds1307_trickle_of_init(struct i2c_client *client,
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, ...@@ -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, ...@@ -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;
if (id) {
chip = &chips[id->driver_data];
ds1307->type = id->driver_data; ds1307->type = id->driver_data;
} else {
const struct acpi_device_id *acpi_id;
acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids),
&client->dev);
if (!acpi_id)
return -ENODEV;
chip = &chips[acpi_id->driver_data];
ds1307->type = acpi_id->driver_data;
}
if (!pdata && client->dev.of_node) if (!pdata)
ds1307_trickle_of_init(client, chip); ds1307_trickle_init(client, chip);
else if (pdata && pdata->trickle_charger_setup) 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) ...@@ -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,
......
...@@ -89,10 +89,8 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time, ...@@ -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);
......
...@@ -67,7 +67,7 @@ ...@@ -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) */
......
...@@ -14,10 +14,12 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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,10 +90,32 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc) ...@@ -64,10 +90,32 @@ 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;
if (rtc->type >= ID_JZ4780)
ret = jz4780_rtc_enable_write(rtc);
if (ret == 0)
ret = jz4740_rtc_wait_write_ready(rtc); 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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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");
...@@ -11,7 +11,7 @@ ...@@ -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) ...@@ -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");
...@@ -12,7 +12,7 @@ ...@@ -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 @@ ...@@ -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
...@@ -37,8 +39,17 @@ ...@@ -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) ...@@ -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) ...@@ -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,8 +247,8 @@ static int mcp795_probe(struct spi_device *spi) ...@@ -169,8 +247,8 @@ 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);
......
...@@ -191,12 +191,19 @@ static int pcf85063_probe(struct i2c_client *client, ...@@ -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);
......
This diff is collapsed.
/* 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 = { ...@@ -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);
/* 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 @@ ...@@ -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 = { ...@@ -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");
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment