diff options
Diffstat (limited to 'drivers/rtc')
34 files changed, 4015 insertions, 1568 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 376322f71..3e84315c6 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -140,7 +140,6 @@ config RTC_DRV_TEST will be called rtc-test. comment "I2C RTC drivers" - depends on I2C if I2C @@ -212,6 +211,15 @@ config RTC_DRV_DS1307 This driver can also be built as a module. If so, the module will be called rtc-ds1307. +config RTC_DRV_DS1307_HWMON + bool "HWMON support for rtc-ds1307" + depends on RTC_DRV_DS1307 && HWMON + depends on !(RTC_DRV_DS1307=y && HWMON=m) + default y + help + Say Y here if you want to expose temperature sensor data on + rtc-ds1307 (only DS3231) + config RTC_DRV_DS1374 tristate "Dallas/Maxim DS1374" help @@ -239,16 +247,6 @@ config RTC_DRV_DS1672 This driver can also be built as a module. If so, the module will be called rtc-ds1672. -config RTC_DRV_DS3232 - tristate "Dallas/Maxim DS3232" - help - If you say yes here you get support for Dallas Semiconductor - DS3232 real-time clock chips. If an interrupt is associated - with the device, the alarm functionality is supported. - - This driver can also be built as a module. If so, the module - will be called rtc-ds3232. - config RTC_DRV_HYM8563 tristate "Haoyu Microelectronics HYM8563" depends on OF @@ -317,10 +315,10 @@ config RTC_DRV_MAX8997 config RTC_DRV_MAX77686 tristate "Maxim MAX77686" - depends on MFD_MAX77686 + depends on MFD_MAX77686 || MFD_MAX77620 help If you say yes here you will get support for the - RTC of Maxim MAX77686 PMIC. + RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC. This driver can also be built as a module. If so, the module will be called rtc-max77686. @@ -335,16 +333,6 @@ config RTC_DRV_RK808 This driver can also be built as a module. If so, the module will be called rk808-rtc. -config RTC_DRV_MAX77802 - tristate "Maxim 77802 RTC" - depends on MFD_MAX77686 - help - If you say yes here you will get support for the - RTC of Maxim MAX77802 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-max77802. - config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help @@ -391,25 +379,6 @@ config RTC_DRV_X1205 This driver can also be built as a module. If so, the module will be called rtc-x1205. -config RTC_DRV_PALMAS - tristate "TI Palmas RTC driver" - depends on MFD_PALMAS - help - If you say yes here you get support for the RTC of TI PALMA series PMIC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-palma. - -config RTC_DRV_PCF2127 - tristate "NXP PCF2127" - help - If you say yes here you get support for the NXP PCF2127/29 RTC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-pcf2127. - config RTC_DRV_PCF8523 tristate "NXP PCF8523" help @@ -419,6 +388,14 @@ config RTC_DRV_PCF8523 This driver can also be built as a module. If so, the module will be called rtc-pcf8523. +config RTC_DRV_PCF85063 + tristate "NXP PCF85063" + help + If you say yes here you get support for the PCF85063 RTC chip + + This driver can also be built as a module. If so, the module + will be called rtc-pcf85063. + config RTC_DRV_PCF8563 tristate "Philips PCF8563/Epson RTC8564" help @@ -429,14 +406,6 @@ config RTC_DRV_PCF8563 This driver can also be built as a module. If so, the module will be called rtc-pcf8563. -config RTC_DRV_PCF85063 - tristate "nxp PCF85063" - help - If you say yes here you get support for the PCF85063 RTC chip - - This driver can also be built as a module. If so, the module - will be called rtc-pcf85063. - config RTC_DRV_PCF8583 tristate "Philips PCF8583" help @@ -501,6 +470,16 @@ config RTC_DRV_TWL4030 This driver can also be built as a module. If so, the module will be called rtc-twl. +config RTC_DRV_PALMAS + tristate "TI Palmas RTC driver" + depends on MFD_PALMAS + help + If you say yes here you get support for the RTC of TI PALMA series PMIC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-palma. + config RTC_DRV_TPS6586X tristate "TI TPS6586X RTC driver" depends on MFD_TPS6586X @@ -595,14 +574,23 @@ config RTC_DRV_EM3027 will be called rtc-em3027. config RTC_DRV_RV3029C2 - tristate "Micro Crystal RTC" + tristate "Micro Crystal RV3029" help If you say yes here you get support for the Micro Crystal - RV3029-C2 RTC chips. + RV3029 RTC chips. This driver can also be built as a module. If so, the module will be called rtc-rv3029c2. +config RTC_DRV_RV3029_HWMON + bool "HWMON support for RV3029" + depends on RTC_DRV_RV3029C2 && HWMON + depends on !(RTC_DRV_RV3029C2=y && HWMON=m) + default y + help + Say Y here if you want to expose temperature sensor data on + rtc-rv3029. + config RTC_DRV_RV8803 tristate "Micro Crystal RV8803" help @@ -691,15 +679,6 @@ config RTC_DRV_DS1390 This driver can also be built as a module. If so, the module will be called rtc-ds1390. -config RTC_DRV_MAX6902 - tristate "Maxim MAX6902" - help - If you say yes here you will get support for the - Maxim MAX6902 SPI RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-max6902. - config RTC_DRV_R9701 tristate "Epson RTC-9701JE" help @@ -709,6 +688,23 @@ config RTC_DRV_R9701 This driver can also be built as a module. If so, the module will be called rtc-r9701. +config RTC_DRV_RX4581 + tristate "Epson RX-4581" + help + If you say yes here you will get support for the Epson RX-4581. + + This driver can also be built as a module. If so the module + will be called rtc-rx4581. + +config RTC_DRV_RX6110 + tristate "Epson RX-6110" + select REGMAP_SPI + help + If you say yes here you will get support for the Epson RX-6610. + + This driver can also be built as a module. If so the module + will be called rtc-rx6110. + config RTC_DRV_RS5C348 tristate "Ricoh RS5C348A/B" help @@ -718,14 +714,14 @@ config RTC_DRV_RS5C348 This driver can also be built as a module. If so, the module will be called rtc-rs5c348. -config RTC_DRV_DS3234 - tristate "Maxim/Dallas DS3234" +config RTC_DRV_MAX6902 + tristate "Maxim MAX6902" help - If you say yes here you get support for the - Maxim/Dallas DS3234 SPI RTC chip. + If you say yes here you will get support for the + Maxim MAX6902 SPI RTC chip. This driver can also be built as a module. If so, the module - will be called rtc-ds3234. + will be called rtc-max6902. config RTC_DRV_PCF2123 tristate "NXP PCF2123" @@ -736,14 +732,6 @@ config RTC_DRV_PCF2123 This driver can also be built as a module. If so, the module will be called rtc-pcf2123. -config RTC_DRV_RX4581 - tristate "Epson RX-4581" - help - If you say yes here you will get support for the Epson RX-4581. - - This driver can also be built as a module. If so the module - will be called rtc-rx4581. - config RTC_DRV_MCP795 tristate "Microchip MCP795" help @@ -754,6 +742,41 @@ config RTC_DRV_MCP795 endif # SPI_MASTER +# +# Helper to resolve issues with configs that have SPI enabled but I2C +# modular. See SND_SOC_I2C_AND_SPI for more information +# +config RTC_I2C_AND_SPI + tristate + default m if I2C=m + default y if I2C=y + default y if SPI_MASTER=y + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER + +comment "SPI and I2C RTC drivers" + +config RTC_DRV_DS3232 + tristate "Dallas/Maxim DS3232/DS3234" + depends on RTC_I2C_AND_SPI + help + If you say yes here you get support for Dallas Semiconductor + DS3232 and DS3234 real-time clock chips. If an interrupt is associated + with the device, the alarm functionality is supported. + + This driver can also be built as a module. If so, the module + will be called rtc-ds3232. + +config RTC_DRV_PCF2127 + tristate "NXP PCF2127" + depends on RTC_I2C_AND_SPI + help + If you say yes here you get support for the NXP PCF2127/29 RTC + chips. + + This driver can also be built as a module. If so, the module + will be called rtc-pcf2127. + comment "Platform RTC drivers" # this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h> @@ -1087,7 +1110,7 @@ config RTC_DRV_WM8350 config RTC_DRV_SPEAR tristate "SPEAR ST RTC" - depends on PLAT_SPEAR + depends on PLAT_SPEAR || COMPILE_TEST default y help If you say Y here you will get support for the RTC found on @@ -1119,7 +1142,7 @@ config RTC_DRV_AB8500 config RTC_DRV_NUC900 tristate "NUC910/NUC920 RTC driver" - depends on ARCH_W90X900 + depends on ARCH_W90X900 || COMPILE_TEST help If you say yes here you get support for the RTC subsystem of the NUC910/NUC920 used in embedded systems. @@ -1144,9 +1167,19 @@ config RTC_DRV_ZYNQMP comment "on-CPU RTC drivers" +config RTC_DRV_ASM9260 + tristate "Alphascale asm9260 RTC" + depends on MACH_ASM9260 + help + If you say yes here you get support for the RTC on the + Alphascale asm9260 SoC. + + This driver can also be built as a module. If so, the module + will be called rtc-asm9260. + config RTC_DRV_DAVINCI tristate "TI DaVinci RTC" - depends on ARCH_DAVINCI_DM365 + depends on ARCH_DAVINCI_DM365 || COMPILE_TEST help If you say yes here you get support for the RTC on the DaVinci platforms (DM365). @@ -1156,7 +1189,7 @@ config RTC_DRV_DAVINCI config RTC_DRV_DIGICOLOR tristate "Conexant Digicolor RTC" - depends on ARCH_DIGICOLOR + depends on ARCH_DIGICOLOR || COMPILE_TEST help If you say yes here you get support for the RTC on Conexant Digicolor platforms. This currently includes the CX92755 SoC. @@ -1175,7 +1208,7 @@ config RTC_DRV_IMXDI config RTC_DRV_OMAP tristate "TI OMAP Real Time Clock" - depends on ARCH_OMAP || ARCH_DAVINCI + depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST help Say "yes" here to support the on chip real time clock present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. @@ -1192,7 +1225,7 @@ config HAVE_S3C_RTC config RTC_DRV_S3C tristate "Samsung S3C series SoC RTC" - depends on ARCH_S3C64XX || HAVE_S3C_RTC + depends on ARCH_S3C64XX || HAVE_S3C_RTC || COMPILE_TEST help RTC (Realtime Clock) driver for the clock inbuilt into the Samsung S3C24XX series of SoCs. This can provide periodic @@ -1208,7 +1241,7 @@ config RTC_DRV_S3C config RTC_DRV_EP93XX tristate "Cirrus Logic EP93XX" - depends on ARCH_EP93XX + depends on ARCH_EP93XX || COMPILE_TEST help If you say yes here you get support for the RTC embedded in the Cirrus Logic EP93XX processors. @@ -1238,7 +1271,7 @@ config RTC_DRV_SH config RTC_DRV_VR41XX tristate "NEC VR41XX" - depends on CPU_VR41XX + depends on CPU_VR41XX || COMPILE_TEST help If you say Y here you will get access to the real time clock built into your NEC VR41XX CPU. @@ -1268,14 +1301,14 @@ config RTC_DRV_PL031 config RTC_DRV_AT32AP700X tristate "AT32AP700X series RTC" - depends on PLATFORM_AT32AP + depends on PLATFORM_AT32AP || COMPILE_TEST help Driver for the internal RTC (Realtime Clock) on Atmel AVR32 AT32AP700x family processors. config RTC_DRV_AT91RM9200 tristate "AT91RM9200 or some AT91SAM9 RTC" - depends on ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST help Driver for the internal RTC (Realtime Clock) module found on Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips @@ -1283,7 +1316,7 @@ config RTC_DRV_AT91RM9200 config RTC_DRV_AT91SAM9 tristate "AT91SAM9 RTT as RTC" - depends on ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST select MFD_SYSCON help Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which @@ -1325,17 +1358,17 @@ config RTC_DRV_GENERIC tristate "Generic RTC support" # Please consider writing a new RTC driver instead of using the generic # RTC abstraction - depends on PARISC || M68K || PPC || SUPERH32 + depends on PARISC || M68K || PPC || SUPERH32 || COMPILE_TEST help Say Y or M here to enable RTC support on systems using the generic RTC abstraction. If you do not know what you are doing, you should just say Y. config RTC_DRV_PXA - tristate "PXA27x/PXA3xx" - depends on ARCH_PXA - select RTC_DRV_SA1100 - help + tristate "PXA27x/PXA3xx" + depends on ARCH_PXA + select RTC_DRV_SA1100 + help If you say Y here you will get access to the real time clock built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs consisting of an SA1100 compatible RTC and the extended PXA RTC. @@ -1345,7 +1378,7 @@ config RTC_DRV_PXA config RTC_DRV_VT8500 tristate "VIA/WonderMedia 85xx SoC RTC" - depends on ARCH_VT8500 + depends on ARCH_VT8500 || COMPILE_TEST help If you say Y here you will get access to the real time clock built into your VIA VT8500 SoC or its relatives. @@ -1360,14 +1393,15 @@ config RTC_DRV_SUN4V config RTC_DRV_SUN6I tristate "Allwinner A31 RTC" - depends on MACH_SUN6I || MACH_SUN8I + default MACH_SUN6I || MACH_SUN8I || COMPILE_TEST + depends on ARCH_SUNXI help - If you say Y here you will get support for the RTC found on - Allwinner A31. + If you say Y here you will get support for the RTC found in + some Allwinner SoCs like the A31 or the A64. config RTC_DRV_SUNXI tristate "Allwinner sun4i/sun7i RTC" - depends on MACH_SUN4I || MACH_SUN7I + depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST help If you say Y here you will get support for the RTC found on Allwinner A10/A20. @@ -1388,7 +1422,7 @@ config RTC_DRV_TX4939 config RTC_DRV_MV tristate "Marvell SoC RTC" - depends on ARCH_DOVE || ARCH_MVEBU + depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST help If you say yes here you will get support for the in-chip RTC that can be found in some of Marvell's SoC devices, such as @@ -1399,7 +1433,7 @@ config RTC_DRV_MV config RTC_DRV_ARMADA38X tristate "Armada 38x Marvell SoC RTC" - depends on ARCH_MVEBU + depends on ARCH_MVEBU || COMPILE_TEST help If you say yes here you will get support for the in-chip RTC that can be found in the Armada 38x Marvell's SoC device @@ -1429,7 +1463,7 @@ config RTC_DRV_PS3 config RTC_DRV_COH901331 tristate "ST-Ericsson COH 901 331 RTC" - depends on ARCH_U300 + depends on ARCH_U300 || COMPILE_TEST help If you say Y here you will get access to ST-Ericsson COH 901 331 RTC clock found in some ST-Ericsson Mobile @@ -1441,7 +1475,7 @@ config RTC_DRV_COH901331 config RTC_DRV_STMP tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" - depends on ARCH_MXS + depends on ARCH_MXS || COMPILE_TEST select STMP_DEVICE help If you say yes here you will get support for the onboard @@ -1476,7 +1510,7 @@ config RTC_DRV_MPC5121 config RTC_DRV_JZ4740 tristate "Ingenic JZ4740 SoC" - depends on MACH_JZ4740 + depends on MACH_JZ4740 || COMPILE_TEST help If you say yes here you get support for the Ingenic JZ4740 SoC RTC controller. @@ -1497,7 +1531,7 @@ config RTC_DRV_LPC24XX so, the module will be called rtc-lpc24xx. config RTC_DRV_LPC32XX - depends on ARCH_LPC32XX + depends on ARCH_LPC32XX || COMPILE_TEST tristate "NXP LPC32XX RTC" help This enables support for the NXP RTC in the LPC32XX @@ -1507,7 +1541,7 @@ config RTC_DRV_LPC32XX config RTC_DRV_PM8XXX tristate "Qualcomm PMIC8XXX RTC" - depends on MFD_PM8XXX || MFD_SPMI_PMIC + depends on MFD_PM8XXX || MFD_SPMI_PMIC || COMPILE_TEST help If you say yes here you get support for the Qualcomm PMIC8XXX RTC. @@ -1517,7 +1551,7 @@ config RTC_DRV_PM8XXX config RTC_DRV_TEGRA tristate "NVIDIA Tegra Internal RTC driver" - depends on ARCH_TEGRA + depends on ARCH_TEGRA || COMPILE_TEST help If you say yes here you get support for the Tegra 200 series internal RTC module. @@ -1603,7 +1637,7 @@ config RTC_DRV_MOXART config RTC_DRV_MT6397 tristate "Mediatek Real Time Clock driver" - depends on MFD_MT6397 || COMPILE_TEST + depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN) help This selects the Mediatek(R) RTC driver. RTC is part of Mediatek MT6397 PMIC. You should enable MT6397 PMIC MFD before select @@ -1622,6 +1656,16 @@ config RTC_DRV_XGENE This driver can also be built as a module, if so, the module will be called "rtc-xgene". +config RTC_DRV_PIC32 + tristate "Microchip PIC32 RTC" + depends on MACH_PIC32 + default y + help + If you say yes here you get support for the PIC32 RTC module. + + This driver can also be built as a module. If so, the module + will be called rtc-pic32 + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 62d61b26c..ea2833723 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o +obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o @@ -59,7 +60,6 @@ obj-$(CONFIG_RTC_DRV_DS1685_FAMILY) += rtc-ds1685.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o -obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o @@ -86,7 +86,6 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o -obj-$(CONFIG_RTC_DRV_MAX77802) += rtc-max77802.o obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o @@ -112,6 +111,7 @@ obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o +obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o @@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o +obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index de86578bc..74fd9746a 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -361,17 +361,4 @@ static int __init rtc_init(void) rtc_dev_init(); return 0; } - -static void __exit rtc_exit(void) -{ - rtc_dev_exit(); - class_destroy(rtc_class); - ida_destroy(&rtc_ida); -} - subsys_initcall(rtc_init); -module_exit(rtc_exit); - -MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); -MODULE_DESCRIPTION("RTC class support"); -MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 5836751b8..9ef5f6f89 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -939,4 +939,58 @@ void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer) mutex_unlock(&rtc->ops_lock); } +/** + * rtc_read_offset - Read the amount of rtc offset in parts per billion + * @ rtc: rtc device to be used + * @ offset: the offset in parts per billion + * + * see below for details. + * + * Kernel interface to read rtc clock offset + * Returns 0 on success, or a negative number on error. + * If read_offset() is not implemented for the rtc, return -EINVAL + */ +int rtc_read_offset(struct rtc_device *rtc, long *offset) +{ + int ret; + + if (!rtc->ops) + return -ENODEV; + + if (!rtc->ops->read_offset) + return -EINVAL; + + mutex_lock(&rtc->ops_lock); + ret = rtc->ops->read_offset(rtc->dev.parent, offset); + mutex_unlock(&rtc->ops_lock); + return ret; +} +/** + * rtc_set_offset - Adjusts the duration of the average second + * @ rtc: rtc device to be used + * @ offset: the offset in parts per billion + * + * Some rtc's allow an adjustment to the average duration of a second + * to compensate for differences in the actual clock rate due to temperature, + * the crystal, capacitor, etc. + * + * Kernel interface to adjust an rtc clock offset. + * Return 0 on success, or a negative number on error. + * If the rtc offset is not setable (or not implemented), return -EINVAL + */ +int rtc_set_offset(struct rtc_device *rtc, long offset) +{ + int ret; + + if (!rtc->ops) + return -ENODEV; + + if (!rtc->ops->set_offset) + return -EINVAL; + + mutex_lock(&rtc->ops_lock); + ret = rtc->ops->set_offset(rtc->dev.parent, offset); + mutex_unlock(&rtc->ops_lock); + return ret; +} diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index d41bbcd65..ba0d61934 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -49,7 +49,20 @@ #define ABX8XX_REG_CD_TIMER_CTL 0x18 +#define ABX8XX_REG_OSC 0x1c +#define ABX8XX_OSC_FOS BIT(3) +#define ABX8XX_OSC_BOS BIT(4) +#define ABX8XX_OSC_ACAL_512 BIT(5) +#define ABX8XX_OSC_ACAL_1024 BIT(6) + +#define ABX8XX_OSC_OSEL BIT(7) + +#define ABX8XX_REG_OSS 0x1d +#define ABX8XX_OSS_OF BIT(1) +#define ABX8XX_OSS_OMODE BIT(4) + #define ABX8XX_REG_CFG_KEY 0x1f +#define ABX8XX_CFG_KEY_OSC 0xa1 #define ABX8XX_CFG_KEY_MISC 0x9d #define ABX8XX_REG_ID0 0x28 @@ -81,6 +94,20 @@ static struct abx80x_cap abx80x_caps[] = { [ABX80X] = {.pn = 0} }; +static int abx80x_is_rc_mode(struct i2c_client *client) +{ + int flags = 0; + + flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); + if (flags < 0) { + dev_err(&client->dev, + "Failed to read autocalibration attribute\n"); + return flags; + } + + return (flags & ABX8XX_OSS_OMODE) ? 1 : 0; +} + static int abx80x_enable_trickle_charger(struct i2c_client *client, u8 trickle_cfg) { @@ -112,7 +139,23 @@ static int abx80x_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); unsigned char buf[8]; - int err; + int err, flags, rc_mode = 0; + + /* Read the Oscillator Failure only in XT mode */ + rc_mode = abx80x_is_rc_mode(client); + if (rc_mode < 0) + return rc_mode; + + if (!rc_mode) { + flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); + if (flags < 0) + return flags; + + if (flags & ABX8XX_OSS_OF) { + dev_err(dev, "Oscillator failure, data is invalid.\n"); + return -EINVAL; + } + } err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_HTH, sizeof(buf), buf); @@ -140,7 +183,7 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct i2c_client *client = to_i2c_client(dev); unsigned char buf[8]; - int err; + int err, flags; if (tm->tm_year < 100) return -EINVAL; @@ -161,6 +204,18 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm) return -EIO; } + /* Clear the OF bit of Oscillator Status Register */ + flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSS); + if (flags < 0) + return flags; + + err = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSS, + flags & ~ABX8XX_OSS_OF); + if (err < 0) { + dev_err(&client->dev, "Unable to write oscillator status register\n"); + return err; + } + return 0; } @@ -248,6 +303,174 @@ static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } +static int abx80x_rtc_set_autocalibration(struct device *dev, + int autocalibration) +{ + struct i2c_client *client = to_i2c_client(dev); + int retval, flags = 0; + + if ((autocalibration != 0) && (autocalibration != 1024) && + (autocalibration != 512)) { + dev_err(dev, "autocalibration value outside permitted range\n"); + return -EINVAL; + } + + flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC); + if (flags < 0) + return flags; + + if (autocalibration == 0) { + flags &= ~(ABX8XX_OSC_ACAL_512 | ABX8XX_OSC_ACAL_1024); + } else if (autocalibration == 1024) { + /* 1024 autocalibration is 0x10 */ + flags |= ABX8XX_OSC_ACAL_1024; + flags &= ~(ABX8XX_OSC_ACAL_512); + } else { + /* 512 autocalibration is 0x11 */ + flags |= (ABX8XX_OSC_ACAL_1024 | ABX8XX_OSC_ACAL_512); + } + + /* Unlock write access to Oscillator Control Register */ + retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY, + ABX8XX_CFG_KEY_OSC); + if (retval < 0) { + dev_err(dev, "Failed to write CONFIG_KEY register\n"); + return retval; + } + + retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags); + + return retval; +} + +static int abx80x_rtc_get_autocalibration(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + int flags = 0, autocalibration; + + flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC); + if (flags < 0) + return flags; + + if (flags & ABX8XX_OSC_ACAL_512) + autocalibration = 512; + else if (flags & ABX8XX_OSC_ACAL_1024) + autocalibration = 1024; + else + autocalibration = 0; + + return autocalibration; +} + +static ssize_t autocalibration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int retval; + unsigned long autocalibration = 0; + + retval = kstrtoul(buf, 10, &autocalibration); + if (retval < 0) { + dev_err(dev, "Failed to store RTC autocalibration attribute\n"); + return -EINVAL; + } + + retval = abx80x_rtc_set_autocalibration(dev, autocalibration); + + return retval ? retval : count; +} + +static ssize_t autocalibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int autocalibration = 0; + + autocalibration = abx80x_rtc_get_autocalibration(dev); + if (autocalibration < 0) { + dev_err(dev, "Failed to read RTC autocalibration\n"); + sprintf(buf, "0\n"); + return autocalibration; + } + + return sprintf(buf, "%d\n", autocalibration); +} + +static DEVICE_ATTR_RW(autocalibration); + +static ssize_t oscillator_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + int retval, flags, rc_mode = 0; + + if (strncmp(buf, "rc", 2) == 0) { + rc_mode = 1; + } else if (strncmp(buf, "xtal", 4) == 0) { + rc_mode = 0; + } else { + dev_err(dev, "Oscillator selection value outside permitted ones\n"); + return -EINVAL; + } + + flags = i2c_smbus_read_byte_data(client, ABX8XX_REG_OSC); + if (flags < 0) + return flags; + + if (rc_mode == 0) + flags &= ~(ABX8XX_OSC_OSEL); + else + flags |= (ABX8XX_OSC_OSEL); + + /* Unlock write access on Oscillator Control register */ + retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_CFG_KEY, + ABX8XX_CFG_KEY_OSC); + if (retval < 0) { + dev_err(dev, "Failed to write CONFIG_KEY register\n"); + return retval; + } + + retval = i2c_smbus_write_byte_data(client, ABX8XX_REG_OSC, flags); + if (retval < 0) { + dev_err(dev, "Failed to write Oscillator Control register\n"); + return retval; + } + + return retval ? retval : count; +} + +static ssize_t oscillator_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc_mode = 0; + struct i2c_client *client = to_i2c_client(dev); + + rc_mode = abx80x_is_rc_mode(client); + + if (rc_mode < 0) { + dev_err(dev, "Failed to read RTC oscillator selection\n"); + sprintf(buf, "\n"); + return rc_mode; + } + + if (rc_mode) + return sprintf(buf, "rc\n"); + else + return sprintf(buf, "xtal\n"); +} + +static DEVICE_ATTR_RW(oscillator); + +static struct attribute *rtc_calib_attrs[] = { + &dev_attr_autocalibration.attr, + &dev_attr_oscillator.attr, + NULL, +}; + +static const struct attribute_group rtc_calib_attr_group = { + .attrs = rtc_calib_attrs, +}; + static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); @@ -303,6 +526,13 @@ static int abx80x_dt_trickle_cfg(struct device_node *np) return (trickle_cfg | i); } +static void rtc_calib_remove_sysfs_group(void *_dev) +{ + struct device *dev = _dev; + + sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group); +} + static int abx80x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -405,6 +635,24 @@ static int abx80x_probe(struct i2c_client *client, } } + /* Export sysfs entries */ + err = sysfs_create_group(&(&client->dev)->kobj, &rtc_calib_attr_group); + if (err) { + dev_err(&client->dev, "Failed to create sysfs group: %d\n", + err); + return err; + } + + err = devm_add_action(&client->dev, rtc_calib_remove_sysfs_group, + &client->dev); + if (err) { + rtc_calib_remove_sysfs_group(&client->dev); + dev_err(&client->dev, + "Failed to add sysfs cleanup action: %d\n", + err); + return err; + } + return 0; } diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c index 56cc58211..6ef0c887e 100644 --- a/drivers/rtc/rtc-as3722.c +++ b/drivers/rtc/rtc-as3722.c @@ -210,7 +210,7 @@ static int as3722_rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq); ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL, - as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, + as3722_alarm_irq, IRQF_ONESHOT, "rtc-alarm", as3722_rtc); if (ret < 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c new file mode 100644 index 000000000..355fdb97a --- /dev/null +++ b/drivers/rtc/rtc-asm9260.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2016 Oleksij Rempel <linux@rempel-privat.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +/* Miscellaneous registers */ +/* Interrupt Location Register */ +#define HW_ILR 0x00 +#define BM_RTCALF BIT(1) +#define BM_RTCCIF BIT(0) + +/* Clock Control Register */ +#define HW_CCR 0x08 +/* Calibration counter disable */ +#define BM_CCALOFF BIT(4) +/* Reset internal oscillator divider */ +#define BM_CTCRST BIT(1) +/* Clock Enable */ +#define BM_CLKEN BIT(0) + +/* Counter Increment Interrupt Register */ +#define HW_CIIR 0x0C +#define BM_CIIR_IMYEAR BIT(7) +#define BM_CIIR_IMMON BIT(6) +#define BM_CIIR_IMDOY BIT(5) +#define BM_CIIR_IMDOW BIT(4) +#define BM_CIIR_IMDOM BIT(3) +#define BM_CIIR_IMHOUR BIT(2) +#define BM_CIIR_IMMIN BIT(1) +#define BM_CIIR_IMSEC BIT(0) + +/* Alarm Mask Register */ +#define HW_AMR 0x10 +#define BM_AMR_IMYEAR BIT(7) +#define BM_AMR_IMMON BIT(6) +#define BM_AMR_IMDOY BIT(5) +#define BM_AMR_IMDOW BIT(4) +#define BM_AMR_IMDOM BIT(3) +#define BM_AMR_IMHOUR BIT(2) +#define BM_AMR_IMMIN BIT(1) +#define BM_AMR_IMSEC BIT(0) +#define BM_AMR_OFF 0xff + +/* Consolidated time registers */ +#define HW_CTIME0 0x14 +#define BM_CTIME0_DOW_S 24 +#define BM_CTIME0_DOW_M 0x7 +#define BM_CTIME0_HOUR_S 16 +#define BM_CTIME0_HOUR_M 0x1f +#define BM_CTIME0_MIN_S 8 +#define BM_CTIME0_MIN_M 0x3f +#define BM_CTIME0_SEC_S 0 +#define BM_CTIME0_SEC_M 0x3f + +#define HW_CTIME1 0x18 +#define BM_CTIME1_YEAR_S 16 +#define BM_CTIME1_YEAR_M 0xfff +#define BM_CTIME1_MON_S 8 +#define BM_CTIME1_MON_M 0xf +#define BM_CTIME1_DOM_S 0 +#define BM_CTIME1_DOM_M 0x1f + +#define HW_CTIME2 0x1C +#define BM_CTIME2_DOY_S 0 +#define BM_CTIME2_DOY_M 0xfff + +/* Time counter registers */ +#define HW_SEC 0x20 +#define HW_MIN 0x24 +#define HW_HOUR 0x28 +#define HW_DOM 0x2C +#define HW_DOW 0x30 +#define HW_DOY 0x34 +#define HW_MONTH 0x38 +#define HW_YEAR 0x3C + +#define HW_CALIBRATION 0x40 +#define BM_CALDIR_BACK BIT(17) +#define BM_CALVAL_M 0x1ffff + +/* General purpose registers */ +#define HW_GPREG0 0x44 +#define HW_GPREG1 0x48 +#define HW_GPREG2 0x4C +#define HW_GPREG3 0x50 +#define HW_GPREG4 0x54 + +/* Alarm register group */ +#define HW_ALSEC 0x60 +#define HW_ALMIN 0x64 +#define HW_ALHOUR 0x68 +#define HW_ALDOM 0x6C +#define HW_ALDOW 0x70 +#define HW_ALDOY 0x74 +#define HW_ALMON 0x78 +#define HW_ALYEAR 0x7C + +struct asm9260_rtc_priv { + struct device *dev; + void __iomem *iobase; + struct rtc_device *rtc; + struct clk *clk; + /* io lock */ + spinlock_t lock; +}; + +static irqreturn_t asm9260_rtc_irq(int irq, void *dev_id) +{ + struct asm9260_rtc_priv *priv = dev_id; + u32 isr; + unsigned long events = 0; + + isr = ioread32(priv->iobase + HW_CIIR); + if (!isr) + return IRQ_NONE; + + iowrite32(0, priv->iobase + HW_CIIR); + + events |= RTC_AF | RTC_IRQF; + + rtc_update_irq(priv->rtc, 1, events); + + return IRQ_HANDLED; +} + +static int asm9260_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + u32 ctime0, ctime1, ctime2; + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + ctime0 = ioread32(priv->iobase + HW_CTIME0); + ctime1 = ioread32(priv->iobase + HW_CTIME1); + ctime2 = ioread32(priv->iobase + HW_CTIME2); + + if (ctime1 != ioread32(priv->iobase + HW_CTIME1)) { + /* + * woops, counter flipped right now. Now we are safe + * to reread. + */ + ctime0 = ioread32(priv->iobase + HW_CTIME0); + ctime1 = ioread32(priv->iobase + HW_CTIME1); + ctime2 = ioread32(priv->iobase + HW_CTIME2); + } + spin_unlock_irqrestore(&priv->lock, irq_flags); + + tm->tm_sec = (ctime0 >> BM_CTIME0_SEC_S) & BM_CTIME0_SEC_M; + tm->tm_min = (ctime0 >> BM_CTIME0_MIN_S) & BM_CTIME0_MIN_M; + tm->tm_hour = (ctime0 >> BM_CTIME0_HOUR_S) & BM_CTIME0_HOUR_M; + tm->tm_wday = (ctime0 >> BM_CTIME0_DOW_S) & BM_CTIME0_DOW_M; + + tm->tm_mday = (ctime1 >> BM_CTIME1_DOM_S) & BM_CTIME1_DOM_M; + tm->tm_mon = (ctime1 >> BM_CTIME1_MON_S) & BM_CTIME1_MON_M; + tm->tm_year = (ctime1 >> BM_CTIME1_YEAR_S) & BM_CTIME1_YEAR_M; + + tm->tm_yday = (ctime2 >> BM_CTIME2_DOY_S) & BM_CTIME2_DOY_M; + + return 0; +} + +static int asm9260_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + /* + * make sure SEC counter will not flip other counter on write time, + * real value will be written at the enf of sequence. + */ + iowrite32(0, priv->iobase + HW_SEC); + + iowrite32(tm->tm_year, priv->iobase + HW_YEAR); + iowrite32(tm->tm_mon, priv->iobase + HW_MONTH); + iowrite32(tm->tm_mday, priv->iobase + HW_DOM); + iowrite32(tm->tm_wday, priv->iobase + HW_DOW); + iowrite32(tm->tm_yday, priv->iobase + HW_DOY); + iowrite32(tm->tm_hour, priv->iobase + HW_HOUR); + iowrite32(tm->tm_min, priv->iobase + HW_MIN); + iowrite32(tm->tm_sec, priv->iobase + HW_SEC); + spin_unlock_irqrestore(&priv->lock, irq_flags); + + return 0; +} + +static int asm9260_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + alrm->time.tm_year = ioread32(priv->iobase + HW_ALYEAR); + alrm->time.tm_mon = ioread32(priv->iobase + HW_ALMON); + alrm->time.tm_mday = ioread32(priv->iobase + HW_ALDOM); + alrm->time.tm_wday = ioread32(priv->iobase + HW_ALDOW); + alrm->time.tm_yday = ioread32(priv->iobase + HW_ALDOY); + alrm->time.tm_hour = ioread32(priv->iobase + HW_ALHOUR); + alrm->time.tm_min = ioread32(priv->iobase + HW_ALMIN); + alrm->time.tm_sec = ioread32(priv->iobase + HW_ALSEC); + + alrm->enabled = ioread32(priv->iobase + HW_AMR) ? 1 : 0; + alrm->pending = ioread32(priv->iobase + HW_CIIR) ? 1 : 0; + spin_unlock_irqrestore(&priv->lock, irq_flags); + + return rtc_valid_tm(&alrm->time); +} + +static int asm9260_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + unsigned long irq_flags; + + spin_lock_irqsave(&priv->lock, irq_flags); + iowrite32(alrm->time.tm_year, priv->iobase + HW_ALYEAR); + iowrite32(alrm->time.tm_mon, priv->iobase + HW_ALMON); + iowrite32(alrm->time.tm_mday, priv->iobase + HW_ALDOM); + iowrite32(alrm->time.tm_wday, priv->iobase + HW_ALDOW); + iowrite32(alrm->time.tm_yday, priv->iobase + HW_ALDOY); + iowrite32(alrm->time.tm_hour, priv->iobase + HW_ALHOUR); + iowrite32(alrm->time.tm_min, priv->iobase + HW_ALMIN); + iowrite32(alrm->time.tm_sec, priv->iobase + HW_ALSEC); + + iowrite32(alrm->enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR); + spin_unlock_irqrestore(&priv->lock, irq_flags); + + return 0; +} + +static int asm9260_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct asm9260_rtc_priv *priv = dev_get_drvdata(dev); + + iowrite32(enabled ? 0 : BM_AMR_OFF, priv->iobase + HW_AMR); + return 0; +} + +static const struct rtc_class_ops asm9260_rtc_ops = { + .read_time = asm9260_rtc_read_time, + .set_time = asm9260_rtc_set_time, + .read_alarm = asm9260_rtc_read_alarm, + .set_alarm = asm9260_rtc_set_alarm, + .alarm_irq_enable = asm9260_alarm_irq_enable, +}; + +static int asm9260_rtc_probe(struct platform_device *pdev) +{ + struct asm9260_rtc_priv *priv; + struct device *dev = &pdev->dev; + struct resource *res; + int irq_alarm, ret; + u32 ccr; + + priv = devm_kzalloc(dev, sizeof(struct asm9260_rtc_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + platform_set_drvdata(pdev, priv); + + irq_alarm = platform_get_irq(pdev, 0); + if (irq_alarm < 0) { + dev_err(dev, "No alarm IRQ resource defined\n"); + return irq_alarm; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->iobase = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->iobase)) + return PTR_ERR(priv->iobase); + + priv->clk = devm_clk_get(dev, "ahb"); + ret = clk_prepare_enable(priv->clk); + if (ret) { + dev_err(dev, "Failed to enable clk!\n"); + return ret; + } + + ccr = ioread32(priv->iobase + HW_CCR); + /* if dev is not enabled, reset it */ + if ((ccr & (BM_CLKEN | BM_CTCRST)) != BM_CLKEN) { + iowrite32(BM_CTCRST, priv->iobase + HW_CCR); + ccr = 0; + } + + iowrite32(BM_CLKEN | ccr, priv->iobase + HW_CCR); + iowrite32(0, priv->iobase + HW_CIIR); + iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR); + + priv->rtc = devm_rtc_device_register(dev, dev_name(dev), + &asm9260_rtc_ops, THIS_MODULE); + if (IS_ERR(priv->rtc)) { + ret = PTR_ERR(priv->rtc); + dev_err(dev, "Failed to register RTC device: %d\n", ret); + goto err_return; + } + + ret = devm_request_threaded_irq(dev, irq_alarm, NULL, + asm9260_rtc_irq, IRQF_ONESHOT, + dev_name(dev), priv); + if (ret < 0) { + dev_err(dev, "can't get irq %i, err %d\n", + irq_alarm, ret); + goto err_return; + } + + return 0; + +err_return: + clk_disable_unprepare(priv->clk); + return ret; +} + +static int asm9260_rtc_remove(struct platform_device *pdev) +{ + struct asm9260_rtc_priv *priv = platform_get_drvdata(pdev); + + /* Disable alarm matching */ + iowrite32(BM_AMR_OFF, priv->iobase + HW_AMR); + clk_disable_unprepare(priv->clk); + return 0; +} + +static const struct of_device_id asm9260_dt_ids[] = { + { .compatible = "alphascale,asm9260-rtc", }, + {} +}; + +static struct platform_driver asm9260_rtc_driver = { + .probe = asm9260_rtc_probe, + .remove = asm9260_rtc_remove, + .driver = { + .name = "asm9260-rtc", + .owner = THIS_MODULE, + .of_match_table = asm9260_dt_ids, + }, +}; + +module_platform_driver(asm9260_rtc_driver); + +MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>"); +MODULE_DESCRIPTION("Alphascale asm9260 SoC Realtime Clock Driver (RTC)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index f39691eea..8e41c4613 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -532,7 +532,7 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj, struct spi_transfer x[2]; int status; - spi = container_of(kobj, struct spi_device, dev.kobj); + spi = to_spi_device(kobj_to_dev(kobj)); addr = DS1305_NVRAM + off; msg_init(&m, x, &addr, count, NULL, buf); @@ -554,7 +554,7 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj, struct spi_transfer x[2]; int status; - spi = container_of(kobj, struct spi_device, dev.kobj); + spi = to_spi_device(kobj_to_dev(kobj)); addr = (DS1305_WRITE | DS1305_NVRAM) + off; msg_init(&m, x, &addr, count, buf, NULL); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index cf685f67b..ecb7dbae9 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -19,6 +19,9 @@ #include <linux/rtc.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/clk-provider.h> /* * We can't determine type by probing, but if we expect pre-Linux code @@ -89,6 +92,7 @@ enum ds_type { # define DS1340_BIT_OSF 0x80 #define DS1337_REG_STATUS 0x0f # define DS1337_BIT_OSF 0x80 +# define DS3231_BIT_EN32KHZ 0x08 # define DS1337_BIT_A2I 0x02 # define DS1337_BIT_A1I 0x01 #define DS1339_REG_ALARM1_SECS 0x07 @@ -118,6 +122,9 @@ struct ds1307 { u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, u8 length, const u8 *values); +#ifdef CONFIG_COMMON_CLK + struct clk_hw clks[2]; +#endif }; struct chip_desc { @@ -842,6 +849,378 @@ out: return; } +/*----------------------------------------------------------------------*/ + +#ifdef CONFIG_RTC_DRV_DS1307_HWMON + +/* + * Temperature sensor support for ds3231 devices. + */ + +#define DS3231_REG_TEMPERATURE 0x11 + +/* + * A user-initiated temperature conversion is not started by this function, + * so the temperature is updated once every 64 seconds. + */ +static int ds3231_hwmon_read_temp(struct device *dev, s32 *mC) +{ + struct ds1307 *ds1307 = dev_get_drvdata(dev); + u8 temp_buf[2]; + s16 temp; + int ret; + + ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE, + sizeof(temp_buf), temp_buf); + if (ret < 0) + return ret; + if (ret != sizeof(temp_buf)) + return -EIO; + + /* + * Temperature is represented as a 10-bit code with a resolution of + * 0.25 degree celsius and encoded in two's complement format. + */ + temp = (temp_buf[0] << 8) | temp_buf[1]; + temp >>= 6; + *mC = temp * 250; + + return 0; +} + +static ssize_t ds3231_hwmon_show_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + s32 temp; + + ret = ds3231_hwmon_read_temp(dev, &temp); + if (ret) + return ret; + + return sprintf(buf, "%d\n", temp); +} +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ds3231_hwmon_show_temp, + NULL, 0); + +static struct attribute *ds3231_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(ds3231_hwmon); + +static void ds1307_hwmon_register(struct ds1307 *ds1307) +{ + struct device *dev; + + if (ds1307->type != ds_3231) + return; + + dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev, + ds1307->client->name, + ds1307, ds3231_hwmon_groups); + if (IS_ERR(dev)) { + dev_warn(&ds1307->client->dev, + "unable to register hwmon device %ld\n", PTR_ERR(dev)); + } +} + +#else + +static void ds1307_hwmon_register(struct ds1307 *ds1307) +{ +} + +#endif /* CONFIG_RTC_DRV_DS1307_HWMON */ + +/*----------------------------------------------------------------------*/ + +/* + * Square-wave output support for DS3231 + * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3231.pdf + */ +#ifdef CONFIG_COMMON_CLK + +enum { + DS3231_CLK_SQW = 0, + DS3231_CLK_32KHZ, +}; + +#define clk_sqw_to_ds1307(clk) \ + container_of(clk, struct ds1307, clks[DS3231_CLK_SQW]) +#define clk_32khz_to_ds1307(clk) \ + container_of(clk, struct ds1307, clks[DS3231_CLK_32KHZ]) + +static int ds3231_clk_sqw_rates[] = { + 1, + 1024, + 4096, + 8192, +}; + +static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value) +{ + struct i2c_client *client = ds1307->client; + struct mutex *lock = &ds1307->rtc->ops_lock; + int control; + int ret; + + mutex_lock(lock); + + control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); + if (control < 0) { + ret = control; + goto out; + } + + control &= ~mask; + control |= value; + + ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control); +out: + mutex_unlock(lock); + + return ret; +} + +static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + int control; + int rate_sel = 0; + + control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL); + if (control < 0) + return control; + if (control & DS1337_BIT_RS1) + rate_sel += 1; + if (control & DS1337_BIT_RS2) + rate_sel += 2; + + return ds3231_clk_sqw_rates[rate_sel]; +} + +static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + + for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) { + if (ds3231_clk_sqw_rates[i] <= rate) + return ds3231_clk_sqw_rates[i]; + } + + return 0; +} + +static int ds3231_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + int control = 0; + int rate_sel; + + for (rate_sel = 0; rate_sel < ARRAY_SIZE(ds3231_clk_sqw_rates); + rate_sel++) { + if (ds3231_clk_sqw_rates[rate_sel] == rate) + break; + } + + if (rate_sel == ARRAY_SIZE(ds3231_clk_sqw_rates)) + return -EINVAL; + + if (rate_sel & 1) + control |= DS1337_BIT_RS1; + if (rate_sel & 2) + control |= DS1337_BIT_RS2; + + return ds1337_write_control(ds1307, DS1337_BIT_RS1 | DS1337_BIT_RS2, + control); +} + +static int ds3231_clk_sqw_prepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + return ds1337_write_control(ds1307, DS1337_BIT_INTCN, 0); +} + +static void ds3231_clk_sqw_unprepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + + ds1337_write_control(ds1307, DS1337_BIT_INTCN, DS1337_BIT_INTCN); +} + +static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw); + int control; + + control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL); + if (control < 0) + return control; + + return !(control & DS1337_BIT_INTCN); +} + +static const struct clk_ops ds3231_clk_sqw_ops = { + .prepare = ds3231_clk_sqw_prepare, + .unprepare = ds3231_clk_sqw_unprepare, + .is_prepared = ds3231_clk_sqw_is_prepared, + .recalc_rate = ds3231_clk_sqw_recalc_rate, + .round_rate = ds3231_clk_sqw_round_rate, + .set_rate = ds3231_clk_sqw_set_rate, +}; + +static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 32768; +} + +static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable) +{ + struct i2c_client *client = ds1307->client; + struct mutex *lock = &ds1307->rtc->ops_lock; + int status; + int ret; + + mutex_lock(lock); + + status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); + if (status < 0) { + ret = status; + goto out; + } + + if (enable) + status |= DS3231_BIT_EN32KHZ; + else + status &= ~DS3231_BIT_EN32KHZ; + + ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status); +out: + mutex_unlock(lock); + + return ret; +} + +static int ds3231_clk_32khz_prepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw); + + return ds3231_clk_32khz_control(ds1307, true); +} + +static void ds3231_clk_32khz_unprepare(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw); + + ds3231_clk_32khz_control(ds1307, false); +} + +static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw) +{ + struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw); + int status; + + status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS); + if (status < 0) + return status; + + return !!(status & DS3231_BIT_EN32KHZ); +} + +static const struct clk_ops ds3231_clk_32khz_ops = { + .prepare = ds3231_clk_32khz_prepare, + .unprepare = ds3231_clk_32khz_unprepare, + .is_prepared = ds3231_clk_32khz_is_prepared, + .recalc_rate = ds3231_clk_32khz_recalc_rate, +}; + +static struct clk_init_data ds3231_clks_init[] = { + [DS3231_CLK_SQW] = { + .name = "ds3231_clk_sqw", + .ops = &ds3231_clk_sqw_ops, + .flags = CLK_IS_ROOT, + }, + [DS3231_CLK_32KHZ] = { + .name = "ds3231_clk_32khz", + .ops = &ds3231_clk_32khz_ops, + .flags = CLK_IS_ROOT, + }, +}; + +static int ds3231_clks_register(struct ds1307 *ds1307) +{ + struct i2c_client *client = ds1307->client; + struct device_node *node = client->dev.of_node; + struct clk_onecell_data *onecell; + int i; + + onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL); + if (!onecell) + return -ENOMEM; + + onecell->clk_num = ARRAY_SIZE(ds3231_clks_init); + onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num, + sizeof(onecell->clks[0]), GFP_KERNEL); + if (!onecell->clks) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(ds3231_clks_init); i++) { + struct clk_init_data init = ds3231_clks_init[i]; + + /* + * Interrupt signal due to alarm conditions and square-wave + * output share same pin, so don't initialize both. + */ + if (i == DS3231_CLK_SQW && test_bit(HAS_ALARM, &ds1307->flags)) + continue; + + /* optional override of the clockname */ + of_property_read_string_index(node, "clock-output-names", i, + &init.name); + ds1307->clks[i].init = &init; + + onecell->clks[i] = devm_clk_register(&client->dev, + &ds1307->clks[i]); + if (IS_ERR(onecell->clks[i])) + return PTR_ERR(onecell->clks[i]); + } + + if (!node) + return 0; + + of_clk_add_provider(node, of_clk_src_onecell_get, onecell); + + return 0; +} + +static void ds1307_clks_register(struct ds1307 *ds1307) +{ + int ret; + + if (ds1307->type != ds_3231) + return; + + ret = ds3231_clks_register(ds1307); + if (ret) { + dev_warn(&ds1307->client->dev, + "unable to register clock device %d\n", ret); + } +} + +#else + +static void ds1307_clks_register(struct ds1307 *ds1307) +{ +} + +#endif /* CONFIG_COMMON_CLK */ + static int ds1307_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -851,6 +1230,7 @@ static int ds1307_probe(struct i2c_client *client, struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); bool want_irq = false; + bool ds1307_can_wakeup_device = false; unsigned char *buf; struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); irq_handler_t irq_handler = ds1307_irq; @@ -898,6 +1278,20 @@ static int ds1307_probe(struct i2c_client *client, ds1307->write_block_data = ds1307_write_block_data; } +#ifdef CONFIG_OF +/* + * For devices with no IRQ directly connected to the SoC, the RTC chip + * can be forced as a wakeup source by stating that explicitly in + * the device's .dts file using the "wakeup-source" boolean property. + * If the "wakeup-source" property is set, don't request an IRQ. + * This will guarantee the 'wakealarm' sysfs entry is available on the device, + * if supported by the RTC. + */ + if (of_property_read_bool(client->dev.of_node, "wakeup-source")) { + ds1307_can_wakeup_device = true; + } +#endif + switch (ds1307->type) { case ds_1337: case ds_1339: @@ -916,11 +1310,13 @@ static int ds1307_probe(struct i2c_client *client, ds1307->regs[0] &= ~DS1337_BIT_nEOSC; /* - * Using IRQ? Disable the square wave and both alarms. + * Using IRQ or defined as wakeup-source? + * Disable the square wave and both alarms. * For some variants, be sure alarms can trigger when we're * running on Vbackup (BBSQI/BBSQW) */ - if (ds1307->client->irq > 0 && chip->alarm) { + if (chip->alarm && (ds1307->client->irq > 0 || + ds1307_can_wakeup_device)) { ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); @@ -1135,6 +1531,14 @@ read_rtc: return PTR_ERR(ds1307->rtc); } + if (ds1307_can_wakeup_device && ds1307->client->irq <= 0) { + /* Disable request for an IRQ */ + want_irq = false; + dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n"); + /* We cannot support UIE mode if we do not have an IRQ line */ + ds1307->rtc->uie_unsupported = 1; + } + if (want_irq) { err = devm_request_threaded_irq(&client->dev, client->irq, NULL, irq_handler, @@ -1182,6 +1586,9 @@ read_rtc: } } + ds1307_hwmon_register(ds1307); + ds1307_clks_register(ds1307); + return 0; exit: diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 08e0ff8c7..1e6cfc84b 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -2161,6 +2161,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev) /* Check for valid RTC data, else, spin forever. */ if (unlikely(!pdev)) { pr_emerg("platform device data not available, spinning forever ...\n"); + while(1); unreachable(); } else { /* Get the rtc data. */ diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 4e99ace66..7edc88972 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -1,19 +1,15 @@ /* - * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C + * RTC client/driver for the Maxim/Dallas DS3232/DS3234 Real-Time Clock * * Copyright (C) 2009-2011 Freescale Semiconductor. * Author: Jack Lan <jack.lan@freescale.com> + * Copyright (C) 2008 MIMOMax Wireless Ltd. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -/* - * It would be more efficient to use i2c msgs/i2c_transfer directly but, as - * recommened in .../Documentation/i2c/writing-clients section - * "Sending and receiving", using SMBus level communication is preferred. - */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -21,10 +17,11 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/i2c.h> +#include <linux/spi/spi.h> #include <linux/rtc.h> #include <linux/bcd.h> -#include <linux/workqueue.h> #include <linux/slab.h> +#include <linux/regmap.h> #define DS3232_REG_SECONDS 0x00 #define DS3232_REG_MINUTES 0x01 @@ -50,39 +47,33 @@ # define DS3232_REG_SR_A1F 0x01 struct ds3232 { - struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + int irq; struct rtc_device *rtc; - struct work_struct work; - /* The mutex protects alarm operations, and prevents a race - * between the enable_irq() in the workqueue and the free_irq() - * in the remove function. - */ - struct mutex mutex; bool suspended; - int exiting; }; -static struct i2c_driver ds3232_driver; - -static int ds3232_check_rtc_status(struct i2c_client *client) +static int ds3232_check_rtc_status(struct device *dev) { + struct ds3232 *ds3232 = dev_get_drvdata(dev); int ret = 0; int control, stat; - stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (stat < 0) - return stat; + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) + return ret; if (stat & DS3232_REG_SR_OSF) - dev_warn(&client->dev, + dev_warn(dev, "oscillator discontinuity flagged, " "time unreliable\n"); stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); - ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); - if (ret < 0) + ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat); + if (ret) return ret; /* If the alarm is pending, clear it before requesting @@ -90,31 +81,28 @@ static int ds3232_check_rtc_status(struct i2c_client *client) * before everything is initialized. */ - control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) - return control; + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) + return ret; control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); control |= DS3232_REG_CR_INTCN; - return i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + return regmap_write(ds3232->regmap, DS3232_REG_CR, control); } static int ds3232_read_time(struct device *dev, struct rtc_time *time) { - struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int ret; u8 buf[7]; unsigned int year, month, day, hour, minute, second; unsigned int week, twelve_hr, am_pm; unsigned int century, add_century = 0; - ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_SECONDS, 7, buf); - - if (ret < 0) + ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_SECONDS, buf, 7); + if (ret) return ret; - if (ret < 7) - return -EIO; second = buf[0]; minute = buf[1]; @@ -159,7 +147,7 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time) static int ds3232_set_time(struct device *dev, struct rtc_time *time) { - struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = dev_get_drvdata(dev); u8 buf[7]; /* Extract time from rtc_time and load into ds3232*/ @@ -179,8 +167,7 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) buf[6] = bin2bcd(time->tm_year); } - return i2c_smbus_write_i2c_block_data(client, - DS3232_REG_SECONDS, 7, buf); + return regmap_bulk_write(ds3232->regmap, DS3232_REG_SECONDS, buf, 7); } /* @@ -190,24 +177,19 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) */ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct i2c_client *client = to_i2c_client(dev); - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int control, stat; int ret; u8 buf[4]; - mutex_lock(&ds3232->mutex); - - ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) goto out; - stat = ret; - ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) goto out; - control = ret; - ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); - if (ret < 0) + ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); + if (ret) goto out; alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F); @@ -226,7 +208,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ret = 0; out: - mutex_unlock(&ds3232->mutex); return ret; } @@ -236,166 +217,129 @@ out: */ static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - struct i2c_client *client = to_i2c_client(dev); - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int control, stat; int ret; u8 buf[4]; - if (client->irq <= 0) + if (ds3232->irq <= 0) return -EINVAL; - mutex_lock(&ds3232->mutex); - buf[0] = bin2bcd(alarm->time.tm_sec); buf[1] = bin2bcd(alarm->time.tm_min); buf[2] = bin2bcd(alarm->time.tm_hour); buf[3] = bin2bcd(alarm->time.tm_mday); /* clear alarm interrupt enable bit */ - ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) goto out; - control = ret; control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); - ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); - if (ret < 0) + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); + if (ret) goto out; /* clear any pending alarm flag */ - ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (ret < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) goto out; - stat = ret; stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); - ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); - if (ret < 0) + ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat); + if (ret) goto out; - ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4); + if (ret) + goto out; if (alarm->enabled) { control |= DS3232_REG_CR_A1IE; - ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); } out: - mutex_unlock(&ds3232->mutex); return ret; } -static void ds3232_update_alarm(struct i2c_client *client) +static int ds3232_update_alarm(struct device *dev, unsigned int enabled) { - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); int control; int ret; - u8 buf[4]; - - mutex_lock(&ds3232->mutex); - - ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); - if (ret < 0) - goto unlock; - - buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[0]; - buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[1]; - buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[2]; - buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? - 0x80 : buf[3]; - - ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); - if (ret < 0) - goto unlock; - control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) - goto unlock; + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) + return ret; - if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) + if (enabled) /* enable alarm1 interrupt */ control |= DS3232_REG_CR_A1IE; else /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); - i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control); -unlock: - mutex_unlock(&ds3232->mutex); + return ret; } static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) { - struct i2c_client *client = to_i2c_client(dev); - struct ds3232 *ds3232 = i2c_get_clientdata(client); + struct ds3232 *ds3232 = dev_get_drvdata(dev); - if (client->irq <= 0) + if (ds3232->irq <= 0) return -EINVAL; - if (enabled) - ds3232->rtc->irq_data |= RTC_AF; - else - ds3232->rtc->irq_data &= ~RTC_AF; - - ds3232_update_alarm(client); - return 0; + return ds3232_update_alarm(dev, enabled); } static irqreturn_t ds3232_irq(int irq, void *dev_id) { - struct i2c_client *client = dev_id; - struct ds3232 *ds3232 = i2c_get_clientdata(client); - - disable_irq_nosync(irq); - - /* - * If rtc as a wakeup source, can't schedule the work - * at system resume flow, because at this time the i2c bus - * has not been resumed. - */ - if (!ds3232->suspended) - schedule_work(&ds3232->work); - - return IRQ_HANDLED; -} - -static void ds3232_work(struct work_struct *work) -{ - struct ds3232 *ds3232 = container_of(work, struct ds3232, work); - struct i2c_client *client = ds3232->client; + struct device *dev = dev_id; + struct ds3232 *ds3232 = dev_get_drvdata(dev); + struct mutex *lock = &ds3232->rtc->ops_lock; + int ret; int stat, control; - mutex_lock(&ds3232->mutex); + mutex_lock(lock); - stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); - if (stat < 0) + ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat); + if (ret) goto unlock; if (stat & DS3232_REG_SR_A1F) { - control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); - if (control < 0) { - pr_warn("Read Control Register error - Disable IRQ%d\n", - client->irq); + ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control); + if (ret) { + dev_warn(ds3232->dev, + "Read Control Register error %d\n", ret); } else { /* disable alarm1 interrupt */ control &= ~(DS3232_REG_CR_A1IE); - i2c_smbus_write_byte_data(client, DS3232_REG_CR, - control); + ret = regmap_write(ds3232->regmap, DS3232_REG_CR, + control); + if (ret) { + dev_warn(ds3232->dev, + "Write Control Register error %d\n", + ret); + goto unlock; + } /* clear the alarm pend flag */ stat &= ~DS3232_REG_SR_A1F; - i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat); + if (ret) { + dev_warn(ds3232->dev, + "Write Status Register error %d\n", + ret); + goto unlock; + } rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); - - if (!ds3232->exiting) - enable_irq(client->irq); } } unlock: - mutex_unlock(&ds3232->mutex); + mutex_unlock(lock); + + return IRQ_HANDLED; } static const struct rtc_class_ops ds3232_rtc_ops = { @@ -406,67 +350,50 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .alarm_irq_enable = ds3232_alarm_irq_enable, }; -static int ds3232_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name) { struct ds3232 *ds3232; int ret; - ds3232 = devm_kzalloc(&client->dev, sizeof(struct ds3232), GFP_KERNEL); + ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL); if (!ds3232) return -ENOMEM; - ds3232->client = client; - i2c_set_clientdata(client, ds3232); - - INIT_WORK(&ds3232->work, ds3232_work); - mutex_init(&ds3232->mutex); + ds3232->regmap = regmap; + ds3232->irq = irq; + ds3232->dev = dev; + dev_set_drvdata(dev, ds3232); - ret = ds3232_check_rtc_status(client); + ret = ds3232_check_rtc_status(dev); if (ret) return ret; - if (client->irq > 0) { - ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, - IRQF_SHARED, "ds3232", client); + if (ds3232->irq > 0) { + ret = devm_request_threaded_irq(dev, ds3232->irq, NULL, + ds3232_irq, + IRQF_SHARED | IRQF_ONESHOT, + name, dev); if (ret) { - dev_err(&client->dev, "unable to request IRQ\n"); - } - device_init_wakeup(&client->dev, 1); - } - ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, - &ds3232_rtc_ops, THIS_MODULE); - return PTR_ERR_OR_ZERO(ds3232->rtc); -} - -static int ds3232_remove(struct i2c_client *client) -{ - struct ds3232 *ds3232 = i2c_get_clientdata(client); - - if (client->irq > 0) { - mutex_lock(&ds3232->mutex); - ds3232->exiting = 1; - mutex_unlock(&ds3232->mutex); - - devm_free_irq(&client->dev, client->irq, client); - cancel_work_sync(&ds3232->work); + ds3232->irq = 0; + dev_err(dev, "unable to request IRQ\n"); + } else + device_init_wakeup(dev, 1); } + ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops, + THIS_MODULE); - return 0; + return PTR_ERR_OR_ZERO(ds3232->rtc); } #ifdef CONFIG_PM_SLEEP static int ds3232_suspend(struct device *dev) { struct ds3232 *ds3232 = dev_get_drvdata(dev); - struct i2c_client *client = to_i2c_client(dev); - if (device_can_wakeup(dev)) { - ds3232->suspended = true; - if (irq_set_irq_wake(client->irq, 1)) { + if (device_may_wakeup(dev)) { + if (enable_irq_wake(ds3232->irq)) dev_warn_once(dev, "Cannot set wakeup source\n"); - ds3232->suspended = false; - } } return 0; @@ -475,16 +402,9 @@ static int ds3232_suspend(struct device *dev) static int ds3232_resume(struct device *dev) { struct ds3232 *ds3232 = dev_get_drvdata(dev); - struct i2c_client *client = to_i2c_client(dev); - if (ds3232->suspended) { - ds3232->suspended = false; - - /* Clear the hardware alarm pend flag */ - schedule_work(&ds3232->work); - - irq_set_irq_wake(client->irq, 0); - } + if (device_may_wakeup(dev)) + disable_irq_wake(ds3232->irq); return 0; } @@ -494,6 +414,27 @@ static const struct dev_pm_ops ds3232_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) }; +#if IS_ENABLED(CONFIG_I2C) + +static int ds3232_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + }; + + regmap = devm_regmap_init_i2c(client, &config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "%s: regmap allocation failed: %ld\n", + __func__, PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return ds3232_probe(&client->dev, regmap, client->irq, client->name); +} + static const struct i2c_device_id ds3232_id[] = { { "ds3232", 0 }, { } @@ -505,13 +446,162 @@ static struct i2c_driver ds3232_driver = { .name = "rtc-ds3232", .pm = &ds3232_pm_ops, }, - .probe = ds3232_probe, - .remove = ds3232_remove, + .probe = ds3232_i2c_probe, .id_table = ds3232_id, }; -module_i2c_driver(ds3232_driver); +static int ds3232_register_driver(void) +{ + return i2c_add_driver(&ds3232_driver); +} + +static void ds3232_unregister_driver(void) +{ + i2c_del_driver(&ds3232_driver); +} + +#else + +static int ds3232_register_driver(void) +{ + return 0; +} + +static void ds3232_unregister_driver(void) +{ +} + +#endif + +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static int ds3234_probe(struct spi_device *spi) +{ + int res; + unsigned int tmp; + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = 0x80, + }; + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n", + __func__, PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + + res = regmap_read(regmap, DS3232_REG_SECONDS, &tmp); + if (res) + return res; + + /* Control settings + * + * CONTROL_REG + * BIT 7 6 5 4 3 2 1 0 + * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE + * + * 0 0 0 1 1 1 0 0 + * + * CONTROL_STAT_REG + * BIT 7 6 5 4 3 2 1 0 + * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F + * + * 1 0 0 0 1 0 0 0 + */ + res = regmap_read(regmap, DS3232_REG_CR, &tmp); + if (res) + return res; + res = regmap_write(regmap, DS3232_REG_CR, tmp & 0x1c); + if (res) + return res; + + res = regmap_read(regmap, DS3232_REG_SR, &tmp); + if (res) + return res; + res = regmap_write(regmap, DS3232_REG_SR, tmp & 0x88); + if (res) + return res; + + /* Print our settings */ + res = regmap_read(regmap, DS3232_REG_CR, &tmp); + if (res) + return res; + dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp); + + res = regmap_read(regmap, DS3232_REG_SR, &tmp); + if (res) + return res; + dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp); + + return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234"); +} + +static struct spi_driver ds3234_driver = { + .driver = { + .name = "ds3234", + }, + .probe = ds3234_probe, +}; + +static int ds3234_register_driver(void) +{ + return spi_register_driver(&ds3234_driver); +} + +static void ds3234_unregister_driver(void) +{ + spi_unregister_driver(&ds3234_driver); +} + +#else + +static int ds3234_register_driver(void) +{ + return 0; +} + +static void ds3234_unregister_driver(void) +{ +} + +#endif + +static int __init ds323x_init(void) +{ + int ret; + + ret = ds3232_register_driver(); + if (ret) { + pr_err("Failed to register ds3232 driver: %d\n", ret); + return ret; + } + + ret = ds3234_register_driver(); + if (ret) { + pr_err("Failed to register ds3234 driver: %d\n", ret); + ds3232_unregister_driver(); + } + + return ret; +} +module_init(ds323x_init) + +static void __exit ds323x_exit(void) +{ + ds3234_unregister_driver(); + ds3232_unregister_driver(); +} +module_exit(ds323x_exit) MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>"); -MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver"); +MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>"); +MODULE_DESCRIPTION("Maxim/Dallas DS3232/DS3234 RTC Driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:ds3234"); diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c deleted file mode 100644 index 570ab28fc..000000000 --- a/drivers/rtc/rtc-ds3234.c +++ /dev/null @@ -1,171 +0,0 @@ -/* rtc-ds3234.c - * - * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal - * and SRAM. - * - * Copyright (C) 2008 MIMOMax Wireless Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/rtc.h> -#include <linux/spi/spi.h> -#include <linux/bcd.h> - -#define DS3234_REG_SECONDS 0x00 -#define DS3234_REG_MINUTES 0x01 -#define DS3234_REG_HOURS 0x02 -#define DS3234_REG_DAY 0x03 -#define DS3234_REG_DATE 0x04 -#define DS3234_REG_MONTH 0x05 -#define DS3234_REG_YEAR 0x06 -#define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month register */ - -#define DS3234_REG_CONTROL 0x0E -#define DS3234_REG_CONT_STAT 0x0F - -static int ds3234_set_reg(struct device *dev, unsigned char address, - unsigned char data) -{ - struct spi_device *spi = to_spi_device(dev); - unsigned char buf[2]; - - /* MSB must be '1' to indicate write */ - buf[0] = address | 0x80; - buf[1] = data; - - return spi_write_then_read(spi, buf, 2, NULL, 0); -} - -static int ds3234_get_reg(struct device *dev, unsigned char address, - unsigned char *data) -{ - struct spi_device *spi = to_spi_device(dev); - - *data = address & 0x7f; - - return spi_write_then_read(spi, data, 1, data, 1); -} - -static int ds3234_read_time(struct device *dev, struct rtc_time *dt) -{ - int err; - unsigned char buf[8]; - struct spi_device *spi = to_spi_device(dev); - - buf[0] = 0x00; /* Start address */ - - err = spi_write_then_read(spi, buf, 1, buf, 8); - if (err != 0) - return err; - - /* Seconds, Minutes, Hours, Day, Date, Month, Year */ - dt->tm_sec = bcd2bin(buf[0]); - dt->tm_min = bcd2bin(buf[1]); - dt->tm_hour = bcd2bin(buf[2] & 0x3f); - dt->tm_wday = bcd2bin(buf[3]) - 1; /* 0 = Sun */ - dt->tm_mday = bcd2bin(buf[4]); - dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */ - dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */ - - return rtc_valid_tm(dt); -} - -static int ds3234_set_time(struct device *dev, struct rtc_time *dt) -{ - ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec)); - ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min)); - ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f); - - /* 0 = Sun */ - ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1)); - ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday)); - - /* 0 = Jan */ - ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1)); - - /* Assume 20YY although we just want to make sure not to go negative. */ - if (dt->tm_year > 100) - dt->tm_year -= 100; - - ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year)); - - return 0; -} - -static const struct rtc_class_ops ds3234_rtc_ops = { - .read_time = ds3234_read_time, - .set_time = ds3234_set_time, -}; - -static int ds3234_probe(struct spi_device *spi) -{ - struct rtc_device *rtc; - unsigned char tmp; - int res; - - spi->mode = SPI_MODE_3; - spi->bits_per_word = 8; - spi_setup(spi); - - res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp); - if (res != 0) - return res; - - /* Control settings - * - * CONTROL_REG - * BIT 7 6 5 4 3 2 1 0 - * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE - * - * 0 0 0 1 1 1 0 0 - * - * CONTROL_STAT_REG - * BIT 7 6 5 4 3 2 1 0 - * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F - * - * 1 0 0 0 1 0 0 0 - */ - ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp); - ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c); - - ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); - ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88); - - /* Print our settings */ - ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp); - dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp); - - ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); - dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp); - - rtc = devm_rtc_device_register(&spi->dev, "ds3234", - &ds3234_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - spi_set_drvdata(spi, rtc); - - return 0; -} - -static struct spi_driver ds3234_driver = { - .driver = { - .name = "ds3234", - }, - .probe = ds3234_probe, -}; - -module_spi_driver(ds3234_driver); - -MODULE_DESCRIPTION("DS3234 SPI RTC driver"); -MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:ds3234"); diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c index e782ebd71..d726c6aa9 100644 --- a/drivers/rtc/rtc-generic.c +++ b/drivers/rtc/rtc-generic.c @@ -9,6 +9,8 @@ #include <linux/platform_device.h> #include <linux/rtc.h> +#if defined(CONFIG_M68K) || defined(CONFIG_PARISC) || \ + defined(CONFIG_PPC) || defined(CONFIG_SUPERH32) #include <asm/rtc.h> static int generic_get_time(struct device *dev, struct rtc_time *tm) @@ -33,13 +35,21 @@ static const struct rtc_class_ops generic_rtc_ops = { .read_time = generic_get_time, .set_time = generic_set_time, }; +#else +#define generic_rtc_ops *(struct rtc_class_ops*)NULL +#endif static int __init generic_rtc_probe(struct platform_device *dev) { struct rtc_device *rtc; + const struct rtc_class_ops *ops; + + ops = dev_get_platdata(&dev->dev); + if (!ops) + ops = &generic_rtc_ops; rtc = devm_rtc_device_register(&dev->dev, "rtc-generic", - &generic_rtc_ops, THIS_MODULE); + ops, THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index a82937e2f..d107a8e72 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -176,7 +176,13 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) bin2bcd(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f); buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f); + /* assume 20YY not 19YY */ + if (tm->tm_year < 100 || tm->tm_year > 199) { + dev_err(&client->dev, "Year must be between 2000 and 2099. It's %d.\n", + tm->tm_year + 1900); + return -EINVAL; + } buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year % 100); if (i2c_transfer(client->adapter, msgs, 1) != 1) { diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 725dccae2..182fdd00e 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -1,5 +1,5 @@ /* - * RTC driver for Maxim MAX77686 + * RTC driver for Maxim MAX77686 and MAX77802 * * Copyright (C) 2012 Samsung Electronics Co.Ltd * @@ -12,8 +12,7 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include <linux/i2c.h> #include <linux/slab.h> #include <linux/rtc.h> #include <linux/delay.h> @@ -24,24 +23,38 @@ #include <linux/irqdomain.h> #include <linux/regmap.h> +#define MAX77686_I2C_ADDR_RTC (0x0C >> 1) +#define MAX77620_I2C_ADDR_RTC 0x68 +#define MAX77686_INVALID_I2C_ADDR (-1) + +/* Define non existing register */ +#define MAX77686_INVALID_REG (-1) + /* RTC Control Register */ #define BCD_EN_SHIFT 0 -#define BCD_EN_MASK (1 << BCD_EN_SHIFT) +#define BCD_EN_MASK BIT(BCD_EN_SHIFT) #define MODEL24_SHIFT 1 -#define MODEL24_MASK (1 << MODEL24_SHIFT) +#define MODEL24_MASK BIT(MODEL24_SHIFT) /* RTC Update Register1 */ #define RTC_UDR_SHIFT 0 -#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +#define RTC_UDR_MASK BIT(RTC_UDR_SHIFT) #define RTC_RBUDR_SHIFT 4 -#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) +#define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT) /* RTC Hour register */ #define HOUR_PM_SHIFT 6 -#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) +#define HOUR_PM_MASK BIT(HOUR_PM_SHIFT) /* RTC Alarm Enable */ #define ALARM_ENABLE_SHIFT 7 -#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) +#define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT) -#define MAX77686_RTC_UPDATE_DELAY 16 +#define REG_RTC_NONE 0xdeadbeef + +/* + * MAX77802 has separate register (RTCAE1) for alarm enable instead + * using 1 bit from registers RTC{SEC,MIN,HOUR,DAY,MONTH,YEAR,DATE} + * as in done in MAX77686. + */ +#define MAX77802_ALARM_ENABLE_VALUE 0x77 enum { RTC_SEC = 0, @@ -54,15 +67,38 @@ enum { RTC_NR_TIME }; +struct max77686_rtc_driver_data { + /* Minimum usecs needed for a RTC update */ + unsigned long delay; + /* Mask used to read RTC registers value */ + u8 mask; + /* Registers offset to I2C addresses map */ + const unsigned int *map; + /* Has a separate alarm enable register? */ + bool alarm_enable_reg; + /* I2C address for RTC block */ + int rtc_i2c_addr; + /* RTC interrupt via platform resource */ + bool rtc_irq_from_platform; + /* Pending alarm status register */ + int alarm_pending_status_reg; + /* RTC IRQ CHIP for regmap */ + const struct regmap_irq_chip *rtc_irq_chip; +}; + struct max77686_rtc_info { struct device *dev; - struct max77686_dev *max77686; struct i2c_client *rtc; struct rtc_device *rtc_dev; struct mutex lock; struct regmap *regmap; + struct regmap *rtc_regmap; + + const struct max77686_rtc_driver_data *drv_data; + struct regmap_irq_chip_data *rtc_irq_data; + int rtc_irq; int virq; int rtc_24hr_mode; }; @@ -72,29 +108,190 @@ enum MAX77686_RTC_OP { MAX77686_RTC_READ, }; +/* These are not registers but just offsets that are mapped to addresses */ +enum max77686_rtc_reg_offset { + REG_RTC_CONTROLM = 0, + REG_RTC_CONTROL, + REG_RTC_UPDATE0, + REG_WTSR_SMPL_CNTL, + REG_RTC_SEC, + REG_RTC_MIN, + REG_RTC_HOUR, + REG_RTC_WEEKDAY, + REG_RTC_MONTH, + REG_RTC_YEAR, + REG_RTC_DATE, + REG_ALARM1_SEC, + REG_ALARM1_MIN, + REG_ALARM1_HOUR, + REG_ALARM1_WEEKDAY, + REG_ALARM1_MONTH, + REG_ALARM1_YEAR, + REG_ALARM1_DATE, + REG_ALARM2_SEC, + REG_ALARM2_MIN, + REG_ALARM2_HOUR, + REG_ALARM2_WEEKDAY, + REG_ALARM2_MONTH, + REG_ALARM2_YEAR, + REG_ALARM2_DATE, + REG_RTC_AE1, + REG_RTC_END, +}; + +/* Maps RTC registers offset to the MAX77686 register addresses */ +static const unsigned int max77686_map[REG_RTC_END] = { + [REG_RTC_CONTROLM] = MAX77686_RTC_CONTROLM, + [REG_RTC_CONTROL] = MAX77686_RTC_CONTROL, + [REG_RTC_UPDATE0] = MAX77686_RTC_UPDATE0, + [REG_WTSR_SMPL_CNTL] = MAX77686_WTSR_SMPL_CNTL, + [REG_RTC_SEC] = MAX77686_RTC_SEC, + [REG_RTC_MIN] = MAX77686_RTC_MIN, + [REG_RTC_HOUR] = MAX77686_RTC_HOUR, + [REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY, + [REG_RTC_MONTH] = MAX77686_RTC_MONTH, + [REG_RTC_YEAR] = MAX77686_RTC_YEAR, + [REG_RTC_DATE] = MAX77686_RTC_DATE, + [REG_ALARM1_SEC] = MAX77686_ALARM1_SEC, + [REG_ALARM1_MIN] = MAX77686_ALARM1_MIN, + [REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR, + [REG_ALARM1_WEEKDAY] = MAX77686_ALARM1_WEEKDAY, + [REG_ALARM1_MONTH] = MAX77686_ALARM1_MONTH, + [REG_ALARM1_YEAR] = MAX77686_ALARM1_YEAR, + [REG_ALARM1_DATE] = MAX77686_ALARM1_DATE, + [REG_ALARM2_SEC] = MAX77686_ALARM2_SEC, + [REG_ALARM2_MIN] = MAX77686_ALARM2_MIN, + [REG_ALARM2_HOUR] = MAX77686_ALARM2_HOUR, + [REG_ALARM2_WEEKDAY] = MAX77686_ALARM2_WEEKDAY, + [REG_ALARM2_MONTH] = MAX77686_ALARM2_MONTH, + [REG_ALARM2_YEAR] = MAX77686_ALARM2_YEAR, + [REG_ALARM2_DATE] = MAX77686_ALARM2_DATE, + [REG_RTC_AE1] = REG_RTC_NONE, +}; + +static const struct regmap_irq max77686_rtc_irqs[] = { + /* RTC interrupts */ + REGMAP_IRQ_REG(0, 0, MAX77686_RTCINT_RTC60S_MSK), + REGMAP_IRQ_REG(1, 0, MAX77686_RTCINT_RTCA1_MSK), + REGMAP_IRQ_REG(2, 0, MAX77686_RTCINT_RTCA2_MSK), + REGMAP_IRQ_REG(3, 0, MAX77686_RTCINT_SMPL_MSK), + REGMAP_IRQ_REG(4, 0, MAX77686_RTCINT_RTC1S_MSK), + REGMAP_IRQ_REG(5, 0, MAX77686_RTCINT_WTSR_MSK), +}; + +static const struct regmap_irq_chip max77686_rtc_irq_chip = { + .name = "max77686-rtc", + .status_base = MAX77686_RTC_INT, + .mask_base = MAX77686_RTC_INTM, + .num_regs = 1, + .irqs = max77686_rtc_irqs, + .num_irqs = ARRAY_SIZE(max77686_rtc_irqs), +}; + +static const struct max77686_rtc_driver_data max77686_drv_data = { + .delay = 16000, + .mask = 0x7f, + .map = max77686_map, + .alarm_enable_reg = false, + .rtc_irq_from_platform = false, + .alarm_pending_status_reg = MAX77686_REG_STATUS2, + .rtc_i2c_addr = MAX77686_I2C_ADDR_RTC, + .rtc_irq_chip = &max77686_rtc_irq_chip, +}; + +static const struct max77686_rtc_driver_data max77620_drv_data = { + .delay = 16000, + .mask = 0x7f, + .map = max77686_map, + .alarm_enable_reg = false, + .rtc_irq_from_platform = true, + .alarm_pending_status_reg = MAX77686_INVALID_REG, + .rtc_i2c_addr = MAX77620_I2C_ADDR_RTC, + .rtc_irq_chip = &max77686_rtc_irq_chip, +}; + +static const unsigned int max77802_map[REG_RTC_END] = { + [REG_RTC_CONTROLM] = MAX77802_RTC_CONTROLM, + [REG_RTC_CONTROL] = MAX77802_RTC_CONTROL, + [REG_RTC_UPDATE0] = MAX77802_RTC_UPDATE0, + [REG_WTSR_SMPL_CNTL] = MAX77802_WTSR_SMPL_CNTL, + [REG_RTC_SEC] = MAX77802_RTC_SEC, + [REG_RTC_MIN] = MAX77802_RTC_MIN, + [REG_RTC_HOUR] = MAX77802_RTC_HOUR, + [REG_RTC_WEEKDAY] = MAX77802_RTC_WEEKDAY, + [REG_RTC_MONTH] = MAX77802_RTC_MONTH, + [REG_RTC_YEAR] = MAX77802_RTC_YEAR, + [REG_RTC_DATE] = MAX77802_RTC_DATE, + [REG_ALARM1_SEC] = MAX77802_ALARM1_SEC, + [REG_ALARM1_MIN] = MAX77802_ALARM1_MIN, + [REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR, + [REG_ALARM1_WEEKDAY] = MAX77802_ALARM1_WEEKDAY, + [REG_ALARM1_MONTH] = MAX77802_ALARM1_MONTH, + [REG_ALARM1_YEAR] = MAX77802_ALARM1_YEAR, + [REG_ALARM1_DATE] = MAX77802_ALARM1_DATE, + [REG_ALARM2_SEC] = MAX77802_ALARM2_SEC, + [REG_ALARM2_MIN] = MAX77802_ALARM2_MIN, + [REG_ALARM2_HOUR] = MAX77802_ALARM2_HOUR, + [REG_ALARM2_WEEKDAY] = MAX77802_ALARM2_WEEKDAY, + [REG_ALARM2_MONTH] = MAX77802_ALARM2_MONTH, + [REG_ALARM2_YEAR] = MAX77802_ALARM2_YEAR, + [REG_ALARM2_DATE] = MAX77802_ALARM2_DATE, + [REG_RTC_AE1] = MAX77802_RTC_AE1, +}; + +static const struct regmap_irq_chip max77802_rtc_irq_chip = { + .name = "max77802-rtc", + .status_base = MAX77802_RTC_INT, + .mask_base = MAX77802_RTC_INTM, + .num_regs = 1, + .irqs = max77686_rtc_irqs, /* same masks as 77686 */ + .num_irqs = ARRAY_SIZE(max77686_rtc_irqs), +}; + +static const struct max77686_rtc_driver_data max77802_drv_data = { + .delay = 200, + .mask = 0xff, + .map = max77802_map, + .alarm_enable_reg = true, + .rtc_irq_from_platform = false, + .alarm_pending_status_reg = MAX77686_REG_STATUS2, + .rtc_i2c_addr = MAX77686_INVALID_I2C_ADDR, + .rtc_irq_chip = &max77802_rtc_irq_chip, +}; + static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm, - int rtc_24hr_mode) + struct max77686_rtc_info *info) { - tm->tm_sec = data[RTC_SEC] & 0x7f; - tm->tm_min = data[RTC_MIN] & 0x7f; - if (rtc_24hr_mode) + u8 mask = info->drv_data->mask; + + tm->tm_sec = data[RTC_SEC] & mask; + tm->tm_min = data[RTC_MIN] & mask; + if (info->rtc_24hr_mode) { tm->tm_hour = data[RTC_HOUR] & 0x1f; - else { + } else { tm->tm_hour = data[RTC_HOUR] & 0x0f; if (data[RTC_HOUR] & HOUR_PM_MASK) tm->tm_hour += 12; } /* Only a single bit is set in data[], so fls() would be equivalent */ - tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f) - 1; + tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1; tm->tm_mday = data[RTC_DATE] & 0x1f; tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; - tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100; + tm->tm_year = data[RTC_YEAR] & mask; tm->tm_yday = 0; tm->tm_isdst = 0; + + /* + * MAX77686 uses 1 bit from sec/min/hour/etc RTC registers and the + * year values are just 0..99 so add 100 to support up to 2099. + */ + if (!info->drv_data->alarm_enable_reg) + tm->tm_year += 100; } -static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data, + struct max77686_rtc_info *info) { data[RTC_SEC] = tm->tm_sec; data[RTC_MIN] = tm->tm_min; @@ -102,35 +299,44 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data) data[RTC_WEEKDAY] = 1 << tm->tm_wday; data[RTC_DATE] = tm->tm_mday; data[RTC_MONTH] = tm->tm_mon + 1; + + if (info->drv_data->alarm_enable_reg) { + data[RTC_YEAR] = tm->tm_year; + return 0; + } + data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; if (tm->tm_year < 100) { - pr_warn("RTC cannot handle the year %d. Assume it's 2000.\n", + dev_err(info->dev, "RTC cannot handle the year %d.\n", 1900 + tm->tm_year); return -EINVAL; } + return 0; } static int max77686_rtc_update(struct max77686_rtc_info *info, - enum MAX77686_RTC_OP op) + enum MAX77686_RTC_OP op) { int ret; unsigned int data; + unsigned long delay = info->drv_data->delay; if (op == MAX77686_RTC_WRITE) data = 1 << RTC_UDR_SHIFT; else data = 1 << RTC_RBUDR_SHIFT; - ret = regmap_update_bits(info->max77686->rtc_regmap, - MAX77686_RTC_UPDATE0, data, data); + ret = regmap_update_bits(info->rtc_regmap, + info->drv_data->map[REG_RTC_UPDATE0], + data, data); if (ret < 0) - dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", - __func__, ret, data); + dev_err(info->dev, "Fail to write update reg(ret=%d, data=0x%x)\n", + ret, data); else { - /* Minimum 16ms delay required before RTC update. */ - msleep(MAX77686_RTC_UPDATE_DELAY); + /* Minimum delay required before RTC update. */ + usleep_range(delay, delay * 2); } return ret; @@ -148,14 +354,15 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_RTC_SEC, data, RTC_NR_TIME); + ret = regmap_bulk_read(info->rtc_regmap, + info->drv_data->map[REG_RTC_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret); + dev_err(info->dev, "Fail to read time reg(%d)\n", ret); goto out; } - max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); + max77686_rtc_data_to_tm(data, tm, info); ret = rtc_valid_tm(tm); @@ -170,17 +377,17 @@ static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) u8 data[RTC_NR_TIME]; int ret; - ret = max77686_rtc_tm_to_data(tm, data); + ret = max77686_rtc_tm_to_data(tm, data, info); if (ret < 0) return ret; mutex_lock(&info->lock); - ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_RTC_SEC, data, RTC_NR_TIME); + ret = regmap_bulk_write(info->rtc_regmap, + info->drv_data->map[REG_RTC_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, - ret); + dev_err(info->dev, "Fail to write time reg(%d)\n", ret); goto out; } @@ -196,6 +403,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct max77686_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_NR_TIME]; unsigned int val; + const unsigned int *map = info->drv_data->map; int i, ret; mutex_lock(&info->lock); @@ -204,29 +412,53 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", - __func__, __LINE__, ret); + dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); goto out; } - max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); + max77686_rtc_data_to_tm(data, &alrm->time, info); alrm->enabled = 0; - for (i = 0; i < RTC_NR_TIME; i++) { - if (data[i] & ALARM_ENABLE_MASK) { + + if (info->drv_data->alarm_enable_reg) { + if (map[REG_RTC_AE1] == REG_RTC_NONE) { + ret = -EINVAL; + dev_err(info->dev, + "alarm enable register not set(%d)\n", ret); + goto out; + } + + ret = regmap_read(info->rtc_regmap, map[REG_RTC_AE1], &val); + if (ret < 0) { + dev_err(info->dev, + "fail to read alarm enable(%d)\n", ret); + goto out; + } + + if (val) alrm->enabled = 1; - break; + } else { + for (i = 0; i < ARRAY_SIZE(data); i++) { + if (data[i] & ALARM_ENABLE_MASK) { + alrm->enabled = 1; + break; + } } } alrm->pending = 0; - ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val); + + if (info->drv_data->alarm_pending_status_reg == MAX77686_INVALID_REG) + goto out; + + ret = regmap_read(info->regmap, + info->drv_data->alarm_pending_status_reg, &val); if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n", - __func__, __LINE__, ret); + dev_err(info->dev, + "Fail to read alarm pending status reg(%d)\n", ret); goto out; } @@ -235,7 +467,7 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) out: mutex_unlock(&info->lock); - return 0; + return ret; } static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) @@ -243,6 +475,7 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) u8 data[RTC_NR_TIME]; int ret, i; struct rtc_time tm; + const unsigned int *map = info->drv_data->map; if (!mutex_is_locked(&info->lock)) dev_warn(info->dev, "%s: should have mutex locked\n", __func__); @@ -251,24 +484,34 @@ static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", - __func__, ret); - goto out; - } + if (info->drv_data->alarm_enable_reg) { + if (map[REG_RTC_AE1] == REG_RTC_NONE) { + ret = -EINVAL; + dev_err(info->dev, + "alarm enable register not set(%d)\n", ret); + goto out; + } + + ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1], 0); + } else { + ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); + if (ret < 0) { + dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); + goto out; + } - max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); + max77686_rtc_data_to_tm(data, &tm, info); - for (i = 0; i < RTC_NR_TIME; i++) - data[i] &= ~ALARM_ENABLE_MASK; + for (i = 0; i < ARRAY_SIZE(data); i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); + } - ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); goto out; } @@ -282,6 +525,7 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) u8 data[RTC_NR_TIME]; int ret; struct rtc_time tm; + const unsigned int *map = info->drv_data->map; if (!mutex_is_locked(&info->lock)) dev_warn(info->dev, "%s: should have mutex locked\n", __func__); @@ -290,32 +534,36 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info) if (ret < 0) goto out; - ret = regmap_bulk_read(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", - __func__, ret); - goto out; + if (info->drv_data->alarm_enable_reg) { + ret = regmap_write(info->rtc_regmap, map[REG_RTC_AE1], + MAX77802_ALARM_ENABLE_VALUE); + } else { + ret = regmap_bulk_read(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); + if (ret < 0) { + dev_err(info->dev, "Fail to read alarm reg(%d)\n", ret); + goto out; + } + + max77686_rtc_data_to_tm(data, &tm, info); + + data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); + data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; + if (data[RTC_MONTH] & 0xf) + data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_YEAR] & info->drv_data->mask) + data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); + if (data[RTC_DATE] & 0x1f) + data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); + + ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); } - max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode); - - data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT); - data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT); - data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT); - data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; - if (data[RTC_MONTH] & 0xf) - data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT); - if (data[RTC_YEAR] & 0x7f) - data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT); - if (data[RTC_DATE] & 0x1f) - data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT); - - ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); goto out; } @@ -330,7 +578,7 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) u8 data[RTC_NR_TIME]; int ret; - ret = max77686_rtc_tm_to_data(&alrm->time, data); + ret = max77686_rtc_tm_to_data(&alrm->time, data, info); if (ret < 0) return ret; @@ -340,12 +588,12 @@ static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret < 0) goto out; - ret = regmap_bulk_write(info->max77686->rtc_regmap, - MAX77686_ALARM1_SEC, data, RTC_NR_TIME); + ret = regmap_bulk_write(info->rtc_regmap, + info->drv_data->map[REG_ALARM1_SEC], + data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write alarm reg(%d)\n", ret); goto out; } @@ -361,7 +609,7 @@ out: } static int max77686_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) + unsigned int enabled) { struct max77686_rtc_info *info = dev_get_drvdata(dev); int ret; @@ -380,7 +628,7 @@ static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data) { struct max77686_rtc_info *info = data; - dev_info(info->dev, "%s:irq(%d)\n", __func__, irq); + dev_dbg(info->dev, "RTC alarm IRQ: %d\n", irq); rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); @@ -406,10 +654,11 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) info->rtc_24hr_mode = 1; - ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2); + ret = regmap_bulk_write(info->rtc_regmap, + info->drv_data->map[REG_RTC_CONTROLM], + data, ARRAY_SIZE(data)); if (ret < 0) { - dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", - __func__, ret); + dev_err(info->dev, "Fail to write controlm reg(%d)\n", ret); return ret; } @@ -417,28 +666,97 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info) return ret; } +static const struct regmap_config max77686_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int max77686_init_rtc_regmap(struct max77686_rtc_info *info) +{ + struct device *parent = info->dev->parent; + struct i2c_client *parent_i2c = to_i2c_client(parent); + int ret; + + if (info->drv_data->rtc_irq_from_platform) { + struct platform_device *pdev = to_platform_device(info->dev); + + info->rtc_irq = platform_get_irq(pdev, 0); + if (info->rtc_irq < 0) { + dev_err(info->dev, "Failed to get rtc interrupts: %d\n", + info->rtc_irq); + return info->rtc_irq; + } + } else { + info->rtc_irq = parent_i2c->irq; + } + + info->regmap = dev_get_regmap(parent, NULL); + if (!info->regmap) { + dev_err(info->dev, "Failed to get rtc regmap\n"); + return -ENODEV; + } + + if (info->drv_data->rtc_i2c_addr == MAX77686_INVALID_I2C_ADDR) { + info->rtc_regmap = info->regmap; + goto add_rtc_irq; + } + + info->rtc = i2c_new_dummy(parent_i2c->adapter, + info->drv_data->rtc_i2c_addr); + if (!info->rtc) { + dev_err(info->dev, "Failed to allocate I2C device for RTC\n"); + return -ENODEV; + } + + info->rtc_regmap = devm_regmap_init_i2c(info->rtc, + &max77686_rtc_regmap_config); + if (IS_ERR(info->rtc_regmap)) { + ret = PTR_ERR(info->rtc_regmap); + dev_err(info->dev, "Failed to allocate RTC regmap: %d\n", ret); + goto err_unregister_i2c; + } + +add_rtc_irq: + ret = regmap_add_irq_chip(info->rtc_regmap, info->rtc_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT | + IRQF_SHARED, 0, info->drv_data->rtc_irq_chip, + &info->rtc_irq_data); + if (ret < 0) { + dev_err(info->dev, "Failed to add RTC irq chip: %d\n", ret); + goto err_unregister_i2c; + } + + return 0; + +err_unregister_i2c: + if (info->rtc) + i2c_unregister_device(info->rtc); + return ret; +} + static int max77686_rtc_probe(struct platform_device *pdev) { - struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent); struct max77686_rtc_info *info; + const struct platform_device_id *id = platform_get_device_id(pdev); int ret; - dev_info(&pdev->dev, "%s\n", __func__); - info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info), - GFP_KERNEL); + GFP_KERNEL); if (!info) return -ENOMEM; mutex_init(&info->lock); info->dev = &pdev->dev; - info->max77686 = max77686; - info->rtc = max77686->rtc; + info->drv_data = (const struct max77686_rtc_driver_data *) + id->driver_data; + + ret = max77686_init_rtc_regmap(info); + if (ret < 0) + return ret; platform_set_drvdata(pdev, info); ret = max77686_rtc_init_reg(info); - if (ret < 0) { dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); goto err_rtc; @@ -446,7 +764,7 @@ static int max77686_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc", + info->rtc_dev = devm_rtc_device_register(&pdev->dev, id->name, &max77686_rtc_ops, THIS_MODULE); if (IS_ERR(info->rtc_dev)) { @@ -457,29 +775,43 @@ static int max77686_rtc_probe(struct platform_device *pdev) goto err_rtc; } - if (!max77686->rtc_irq_data) { - ret = -EINVAL; - dev_err(&pdev->dev, "%s: no RTC regmap IRQ chip\n", __func__); - goto err_rtc; - } - - info->virq = regmap_irq_get_virq(max77686->rtc_irq_data, + info->virq = regmap_irq_get_virq(info->rtc_irq_data, MAX77686_RTCIRQ_RTCA1); if (info->virq <= 0) { ret = -ENXIO; goto err_rtc; } - ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, - max77686_rtc_alarm_irq, 0, "rtc-alarm1", info); - if (ret < 0) + ret = request_threaded_irq(info->virq, NULL, max77686_rtc_alarm_irq, 0, + "rtc-alarm1", info); + if (ret < 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", info->virq, ret); + goto err_rtc; + } + + return 0; err_rtc: + regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data); + if (info->rtc) + i2c_unregister_device(info->rtc); + return ret; } +static int max77686_rtc_remove(struct platform_device *pdev) +{ + struct max77686_rtc_info *info = platform_get_drvdata(pdev); + + free_irq(info->virq, info); + regmap_del_irq_chip(info->rtc_irq, info->rtc_irq_data); + if (info->rtc) + i2c_unregister_device(info->rtc); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int max77686_rtc_suspend(struct device *dev) { @@ -508,7 +840,9 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops, max77686_rtc_suspend, max77686_rtc_resume); static const struct platform_device_id rtc_id[] = { - { "max77686-rtc", 0 }, + { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, }, + { "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, }, + { "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data, }, {}, }; MODULE_DEVICE_TABLE(platform, rtc_id); @@ -519,6 +853,7 @@ static struct platform_driver max77686_rtc_driver = { .pm = &max77686_rtc_pm_ops, }, .probe = max77686_rtc_probe, + .remove = max77686_rtc_remove, .id_table = rtc_id, }; diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c deleted file mode 100644 index 82ffcc5a5..000000000 --- a/drivers/rtc/rtc-max77802.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * RTC driver for Maxim MAX77802 - * - * Copyright (C) 2013 Google, Inc - * - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * - * based on rtc-max8997.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <linux/slab.h> -#include <linux/rtc.h> -#include <linux/delay.h> -#include <linux/mutex.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/mfd/max77686-private.h> -#include <linux/irqdomain.h> -#include <linux/regmap.h> - -/* RTC Control Register */ -#define BCD_EN_SHIFT 0 -#define BCD_EN_MASK (1 << BCD_EN_SHIFT) -#define MODEL24_SHIFT 1 -#define MODEL24_MASK (1 << MODEL24_SHIFT) -/* RTC Update Register1 */ -#define RTC_UDR_SHIFT 0 -#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) -#define RTC_RBUDR_SHIFT 4 -#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT) -/* RTC Hour register */ -#define HOUR_PM_SHIFT 6 -#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) -/* RTC Alarm Enable */ -#define ALARM_ENABLE_SHIFT 7 -#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) - -/* For the RTCAE1 register, we write this value to enable the alarm */ -#define ALARM_ENABLE_VALUE 0x77 - -#define MAX77802_RTC_UPDATE_DELAY_US 200 - -enum { - RTC_SEC = 0, - RTC_MIN, - RTC_HOUR, - RTC_WEEKDAY, - RTC_MONTH, - RTC_YEAR, - RTC_DATE, - RTC_NR_TIME -}; - -struct max77802_rtc_info { - struct device *dev; - struct max77686_dev *max77802; - struct i2c_client *rtc; - struct rtc_device *rtc_dev; - struct mutex lock; - - struct regmap *regmap; - - int virq; - int rtc_24hr_mode; -}; - -enum MAX77802_RTC_OP { - MAX77802_RTC_WRITE, - MAX77802_RTC_READ, -}; - -static void max77802_rtc_data_to_tm(u8 *data, struct rtc_time *tm, - int rtc_24hr_mode) -{ - tm->tm_sec = data[RTC_SEC] & 0xff; - tm->tm_min = data[RTC_MIN] & 0xff; - if (rtc_24hr_mode) - tm->tm_hour = data[RTC_HOUR] & 0x1f; - else { - tm->tm_hour = data[RTC_HOUR] & 0x0f; - if (data[RTC_HOUR] & HOUR_PM_MASK) - tm->tm_hour += 12; - } - - /* Only a single bit is set in data[], so fls() would be equivalent */ - tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0xff) - 1; - tm->tm_mday = data[RTC_DATE] & 0x1f; - tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; - - tm->tm_year = data[RTC_YEAR] & 0xff; - tm->tm_yday = 0; - tm->tm_isdst = 0; -} - -static int max77802_rtc_tm_to_data(struct rtc_time *tm, u8 *data) -{ - data[RTC_SEC] = tm->tm_sec; - data[RTC_MIN] = tm->tm_min; - data[RTC_HOUR] = tm->tm_hour; - data[RTC_WEEKDAY] = 1 << tm->tm_wday; - data[RTC_DATE] = tm->tm_mday; - data[RTC_MONTH] = tm->tm_mon + 1; - data[RTC_YEAR] = tm->tm_year; - - return 0; -} - -static int max77802_rtc_update(struct max77802_rtc_info *info, - enum MAX77802_RTC_OP op) -{ - int ret; - unsigned int data; - - if (op == MAX77802_RTC_WRITE) - data = 1 << RTC_UDR_SHIFT; - else - data = 1 << RTC_RBUDR_SHIFT; - - ret = regmap_update_bits(info->max77802->regmap, - MAX77802_RTC_UPDATE0, data, data); - if (ret < 0) - dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n", - __func__, ret, data); - else { - /* Minimum delay required before RTC update. */ - usleep_range(MAX77802_RTC_UPDATE_DELAY_US, - MAX77802_RTC_UPDATE_DELAY_US * 2); - } - - return ret; -} - -static int max77802_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - int ret; - - mutex_lock(&info->lock); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_bulk_read(info->max77802->regmap, - MAX77802_RTC_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, - ret); - goto out; - } - - max77802_rtc_data_to_tm(data, tm, info->rtc_24hr_mode); - - ret = rtc_valid_tm(tm); - -out: - mutex_unlock(&info->lock); - return ret; -} - -static int max77802_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - int ret; - - ret = max77802_rtc_tm_to_data(tm, data); - if (ret < 0) - return ret; - - mutex_lock(&info->lock); - - ret = regmap_bulk_write(info->max77802->regmap, - MAX77802_RTC_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__, - ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); - -out: - mutex_unlock(&info->lock); - return ret; -} - -static int max77802_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - unsigned int val; - int ret; - - mutex_lock(&info->lock); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_bulk_read(info->max77802->regmap, - MAX77802_ALARM1_SEC, data, RTC_NR_TIME); - if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n", - __func__, __LINE__, ret); - goto out; - } - - max77802_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); - - alrm->enabled = 0; - ret = regmap_read(info->max77802->regmap, - MAX77802_RTC_AE1, &val); - if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read alarm enable(%d)\n", - __func__, __LINE__, ret); - goto out; - } - if (val) - alrm->enabled = 1; - - alrm->pending = 0; - ret = regmap_read(info->max77802->regmap, MAX77802_REG_STATUS2, &val); - if (ret < 0) { - dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n", - __func__, __LINE__, ret); - goto out; - } - - if (val & (1 << 2)) /* RTCA1 */ - alrm->pending = 1; - -out: - mutex_unlock(&info->lock); - return 0; -} - -static int max77802_rtc_stop_alarm(struct max77802_rtc_info *info) -{ - int ret; - - if (!mutex_is_locked(&info->lock)) - dev_warn(info->dev, "%s: should have mutex locked\n", __func__); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_write(info->max77802->regmap, - MAX77802_RTC_AE1, 0); - if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); -out: - return ret; -} - -static int max77802_rtc_start_alarm(struct max77802_rtc_info *info) -{ - int ret; - - if (!mutex_is_locked(&info->lock)) - dev_warn(info->dev, "%s: should have mutex locked\n", - __func__); - - ret = max77802_rtc_update(info, MAX77802_RTC_READ); - if (ret < 0) - goto out; - - ret = regmap_write(info->max77802->regmap, - MAX77802_RTC_AE1, - ALARM_ENABLE_VALUE); - - if (ret < 0) { - dev_err(info->dev, "%s: fail to read alarm reg(%d)\n", - __func__, ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); -out: - return ret; -} - -static int max77802_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - u8 data[RTC_NR_TIME]; - int ret; - - ret = max77802_rtc_tm_to_data(&alrm->time, data); - if (ret < 0) - return ret; - - mutex_lock(&info->lock); - - ret = max77802_rtc_stop_alarm(info); - if (ret < 0) - goto out; - - ret = regmap_bulk_write(info->max77802->regmap, - MAX77802_ALARM1_SEC, data, RTC_NR_TIME); - - if (ret < 0) { - dev_err(info->dev, "%s: fail to write alarm reg(%d)\n", - __func__, ret); - goto out; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); - if (ret < 0) - goto out; - - if (alrm->enabled) - ret = max77802_rtc_start_alarm(info); -out: - mutex_unlock(&info->lock); - return ret; -} - -static int max77802_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) -{ - struct max77802_rtc_info *info = dev_get_drvdata(dev); - int ret; - - mutex_lock(&info->lock); - if (enabled) - ret = max77802_rtc_start_alarm(info); - else - ret = max77802_rtc_stop_alarm(info); - mutex_unlock(&info->lock); - - return ret; -} - -static irqreturn_t max77802_rtc_alarm_irq(int irq, void *data) -{ - struct max77802_rtc_info *info = data; - - dev_dbg(info->dev, "%s:irq(%d)\n", __func__, irq); - - rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); - - return IRQ_HANDLED; -} - -static const struct rtc_class_ops max77802_rtc_ops = { - .read_time = max77802_rtc_read_time, - .set_time = max77802_rtc_set_time, - .read_alarm = max77802_rtc_read_alarm, - .set_alarm = max77802_rtc_set_alarm, - .alarm_irq_enable = max77802_rtc_alarm_irq_enable, -}; - -static int max77802_rtc_init_reg(struct max77802_rtc_info *info) -{ - u8 data[2]; - int ret; - - max77802_rtc_update(info, MAX77802_RTC_READ); - - /* Set RTC control register : Binary mode, 24hour mdoe */ - data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); - data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); - - info->rtc_24hr_mode = 1; - - ret = regmap_bulk_write(info->max77802->regmap, - MAX77802_RTC_CONTROLM, data, ARRAY_SIZE(data)); - if (ret < 0) { - dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", - __func__, ret); - return ret; - } - - ret = max77802_rtc_update(info, MAX77802_RTC_WRITE); - return ret; -} - -static int max77802_rtc_probe(struct platform_device *pdev) -{ - struct max77686_dev *max77802 = dev_get_drvdata(pdev->dev.parent); - struct max77802_rtc_info *info; - int ret; - - dev_dbg(&pdev->dev, "%s\n", __func__); - - info = devm_kzalloc(&pdev->dev, sizeof(struct max77802_rtc_info), - GFP_KERNEL); - if (!info) - return -ENOMEM; - - mutex_init(&info->lock); - info->dev = &pdev->dev; - info->max77802 = max77802; - info->rtc = max77802->i2c; - - platform_set_drvdata(pdev, info); - - ret = max77802_rtc_init_reg(info); - - if (ret < 0) { - dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret); - return ret; - } - - device_init_wakeup(&pdev->dev, 1); - - info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77802-rtc", - &max77802_rtc_ops, THIS_MODULE); - - if (IS_ERR(info->rtc_dev)) { - ret = PTR_ERR(info->rtc_dev); - dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); - if (ret == 0) - ret = -EINVAL; - return ret; - } - - if (!max77802->rtc_irq_data) { - dev_err(&pdev->dev, "No RTC regmap IRQ chip\n"); - return -EINVAL; - } - - info->virq = regmap_irq_get_virq(max77802->rtc_irq_data, - MAX77686_RTCIRQ_RTCA1); - - if (info->virq <= 0) { - dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n", - MAX77686_RTCIRQ_RTCA1); - return -EINVAL; - } - - ret = devm_request_threaded_irq(&pdev->dev, info->virq, NULL, - max77802_rtc_alarm_irq, 0, "rtc-alarm1", - info); - if (ret < 0) - dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", - info->virq, ret); - - return ret; -} - -#ifdef CONFIG_PM_SLEEP -static int max77802_rtc_suspend(struct device *dev) -{ - if (device_may_wakeup(dev)) { - struct max77802_rtc_info *info = dev_get_drvdata(dev); - - return enable_irq_wake(info->virq); - } - - return 0; -} - -static int max77802_rtc_resume(struct device *dev) -{ - if (device_may_wakeup(dev)) { - struct max77802_rtc_info *info = dev_get_drvdata(dev); - - return disable_irq_wake(info->virq); - } - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(max77802_rtc_pm_ops, - max77802_rtc_suspend, max77802_rtc_resume); - -static const struct platform_device_id rtc_id[] = { - { "max77802-rtc", 0 }, - {}, -}; -MODULE_DEVICE_TABLE(platform, rtc_id); - -static struct platform_driver max77802_rtc_driver = { - .driver = { - .name = "max77802-rtc", - .pm = &max77802_rtc_pm_ops, - }, - .probe = max77802_rtc_probe, - .id_table = rtc_id, -}; - -module_platform_driver(max77802_rtc_driver); - -MODULE_DESCRIPTION("Maxim MAX77802 RTC driver"); -MODULE_AUTHOR("Simon Glass <sjg@chromium.org>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 1c91ce8a6..025bb33b9 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -20,6 +20,7 @@ #include <linux/printk.h> #include <linux/spi/spi.h> #include <linux/rtc.h> +#include <linux/of.h> /* MCP795 Instructions, see datasheet table 3-1 */ #define MCP795_EEREAD 0x03 @@ -183,9 +184,18 @@ static int mcp795_probe(struct spi_device *spi) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id mcp795_of_match[] = { + { .compatible = "maxim,mcp795" }, + { } +}; +MODULE_DEVICE_TABLE(of, mcp795_of_match); +#endif + static struct spi_driver mcp795_driver = { .driver = { .name = "rtc-mcp795", + .of_match_table = of_match_ptr(mcp795_of_match), }, .probe = mcp795_probe, }; diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 06a5c52b2..44f622c3e 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -419,4 +419,3 @@ module_platform_driver(mtk_rtc_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Tianping Fang <tianping.fang@mediatek.com>"); MODULE_DESCRIPTION("RTC Driver for MediaTek MT6397 PMIC"); -MODULE_ALIAS("platform:mt6397-rtc"); diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index 7ea2c471f..6080e0ede 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -311,8 +311,7 @@ static int palmas_rtc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL, palmas_rtc_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT | - IRQF_EARLY_RESUME, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, dev_name(&pdev->dev), palmas_rtc); if (ret < 0) { dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret); diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index ea8a31c91..da27738b1 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -48,6 +48,7 @@ #define DRV_VERSION "0.6" +/* REGISTERS */ #define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */ #define PCF2123_REG_CTRL2 (0x01) /* Control Register 2 */ #define PCF2123_REG_SC (0x02) /* datetime */ @@ -57,10 +58,54 @@ #define PCF2123_REG_DW (0x06) #define PCF2123_REG_MO (0x07) #define PCF2123_REG_YR (0x08) +#define PCF2123_REG_ALRM_MN (0x09) /* Alarm Registers */ +#define PCF2123_REG_ALRM_HR (0x0a) +#define PCF2123_REG_ALRM_DM (0x0b) +#define PCF2123_REG_ALRM_DW (0x0c) +#define PCF2123_REG_OFFSET (0x0d) /* Clock Rate Offset Register */ +#define PCF2123_REG_TMR_CLKOUT (0x0e) /* Timer Registers */ +#define PCF2123_REG_CTDWN_TMR (0x0f) + +/* PCF2123_REG_CTRL1 BITS */ +#define CTRL1_CLEAR (0) /* Clear */ +#define CTRL1_CORR_INT BIT(1) /* Correction irq enable */ +#define CTRL1_12_HOUR BIT(2) /* 12 hour time */ +#define CTRL1_SW_RESET (BIT(3) | BIT(4) | BIT(6)) /* Software reset */ +#define CTRL1_STOP BIT(5) /* Stop the clock */ +#define CTRL1_EXT_TEST BIT(7) /* External clock test mode */ + +/* PCF2123_REG_CTRL2 BITS */ +#define CTRL2_TIE BIT(0) /* Countdown timer irq enable */ +#define CTRL2_AIE BIT(1) /* Alarm irq enable */ +#define CTRL2_TF BIT(2) /* Countdown timer flag */ +#define CTRL2_AF BIT(3) /* Alarm flag */ +#define CTRL2_TI_TP BIT(4) /* Irq pin generates pulse */ +#define CTRL2_MSF BIT(5) /* Minute or second irq flag */ +#define CTRL2_SI BIT(6) /* Second irq enable */ +#define CTRL2_MI BIT(7) /* Minute irq enable */ + +/* PCF2123_REG_SC BITS */ +#define OSC_HAS_STOPPED BIT(7) /* Clock has been stopped */ + +/* PCF2123_REG_ALRM_XX BITS */ +#define ALRM_ENABLE BIT(7) /* MN, HR, DM, or DW alarm enable */ + +/* PCF2123_REG_TMR_CLKOUT BITS */ +#define CD_TMR_4096KHZ (0) /* 4096 KHz countdown timer */ +#define CD_TMR_64HZ (1) /* 64 Hz countdown timer */ +#define CD_TMR_1HZ (2) /* 1 Hz countdown timer */ +#define CD_TMR_60th_HZ (3) /* 60th Hz countdown timer */ +#define CD_TMR_TE BIT(3) /* Countdown timer enable */ + +/* PCF2123_REG_OFFSET BITS */ +#define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */ +#define OFFSET_COARSE BIT(7) /* Coarse mode offset */ +#define OFFSET_STEP (2170) /* Offset step in parts per billion */ + +/* READ/WRITE ADDRESS BITS */ +#define PCF2123_WRITE BIT(4) +#define PCF2123_READ (BIT(4) | BIT(7)) -#define PCF2123_SUBADDR (1 << 4) -#define PCF2123_WRITE ((0 << 7) | PCF2123_SUBADDR) -#define PCF2123_READ ((1 << 7) | PCF2123_SUBADDR) static struct spi_driver pcf2123_driver; @@ -84,12 +129,44 @@ static inline void pcf2123_delay_trec(void) ndelay(30); } +static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size) +{ + struct spi_device *spi = to_spi_device(dev); + int ret; + + reg |= PCF2123_READ; + ret = spi_write_then_read(spi, ®, 1, rxbuf, size); + pcf2123_delay_trec(); + + return ret; +} + +static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size) +{ + struct spi_device *spi = to_spi_device(dev); + int ret; + + txbuf[0] |= PCF2123_WRITE; + ret = spi_write(spi, txbuf, size); + pcf2123_delay_trec(); + + return ret; +} + +static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val) +{ + u8 txbuf[2]; + + txbuf[0] = reg; + txbuf[1] = val; + return pcf2123_write(dev, txbuf, sizeof(txbuf)); +} + static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, char *buffer) { - struct spi_device *spi = to_spi_device(dev); struct pcf2123_sysfs_reg *r; - u8 txbuf[1], rxbuf[1]; + u8 rxbuf[1]; unsigned long reg; int ret; @@ -99,19 +176,16 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, if (ret) return ret; - txbuf[0] = PCF2123_READ | reg; - ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1); + ret = pcf2123_read(dev, reg, rxbuf, 1); if (ret < 0) return -EIO; - pcf2123_delay_trec(); + return sprintf(buffer, "0x%x\n", rxbuf[0]); } static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count) { - struct spi_device *spi = to_spi_device(dev); struct pcf2123_sysfs_reg *r; - u8 txbuf[2]; unsigned long reg; unsigned long val; @@ -127,27 +201,78 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; - txbuf[0] = PCF2123_WRITE | reg; - txbuf[1] = val; - ret = spi_write(spi, txbuf, sizeof(txbuf)); + pcf2123_write_reg(dev, reg, val); if (ret < 0) return -EIO; - pcf2123_delay_trec(); return count; } +static int pcf2123_read_offset(struct device *dev, long *offset) +{ + int ret; + s8 reg; + + ret = pcf2123_read(dev, PCF2123_REG_OFFSET, ®, 1); + if (ret < 0) + return ret; + + if (reg & OFFSET_COARSE) + reg <<= 1; /* multiply by 2 and sign extend */ + else + reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */ + + *offset = ((long)reg) * OFFSET_STEP; + + return 0; +} + +/* + * The offset register is a 7 bit signed value with a coarse bit in bit 7. + * The main difference between the two is normal offset adjusts the first + * second of n minutes every other hour, with 61, 62 and 63 being shoved + * into the 60th minute. + * The coarse adjustment does the same, but every hour. + * the two overlap, with every even normal offset value corresponding + * to a coarse offset. Based on this algorithm, it seems that despite the + * name, coarse offset is a better fit for overlapping values. + */ +static int pcf2123_set_offset(struct device *dev, long offset) +{ + s8 reg; + + if (offset > OFFSET_STEP * 127) + reg = 127; + else if (offset < OFFSET_STEP * -128) + reg = -128; + else + reg = (s8)((offset + (OFFSET_STEP >> 1)) / OFFSET_STEP); + + /* choose fine offset only for odd values in the normal range */ + if (reg & 1 && reg <= 63 && reg >= -64) { + /* Normal offset. Clear the coarse bit */ + reg &= ~OFFSET_COARSE; + } else { + /* Coarse offset. Divide by 2 and set the coarse bit */ + reg >>= 1; + reg |= OFFSET_COARSE; + } + + return pcf2123_write_reg(dev, PCF2123_REG_OFFSET, reg); +} + static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct spi_device *spi = to_spi_device(dev); - u8 txbuf[1], rxbuf[7]; + u8 rxbuf[7]; int ret; - txbuf[0] = PCF2123_READ | PCF2123_REG_SC; - ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), - rxbuf, sizeof(rxbuf)); + ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf)); if (ret < 0) return ret; - pcf2123_delay_trec(); + + if (rxbuf[0] & OSC_HAS_STOPPED) { + dev_info(dev, "clock was stopped. Time is not valid\n"); + return -EINVAL; + } tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F); tm->tm_min = bcd2bin(rxbuf[1] & 0x7F); @@ -170,7 +295,6 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct spi_device *spi = to_spi_device(dev); u8 txbuf[8]; int ret; @@ -181,15 +305,12 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); /* Stop the counter first */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x20; - ret = spi_write(spi, txbuf, 2); + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP); if (ret < 0) return ret; - pcf2123_delay_trec(); /* Set the new time */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_SC; + txbuf[0] = PCF2123_REG_SC; txbuf[1] = bin2bcd(tm->tm_sec & 0x7F); txbuf[2] = bin2bcd(tm->tm_min & 0x7F); txbuf[3] = bin2bcd(tm->tm_hour & 0x3F); @@ -198,18 +319,48 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */ txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100); - ret = spi_write(spi, txbuf, sizeof(txbuf)); + ret = pcf2123_write(dev, txbuf, sizeof(txbuf)); if (ret < 0) return ret; - pcf2123_delay_trec(); /* Start the counter */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x00; - ret = spi_write(spi, txbuf, 2); + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); + if (ret < 0) + return ret; + + return 0; +} + +static int pcf2123_reset(struct device *dev) +{ + int ret; + u8 rxbuf[2]; + + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET); + if (ret < 0) + return ret; + + /* Stop the counter */ + dev_dbg(dev, "stopping RTC\n"); + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP); + if (ret < 0) + return ret; + + /* See if the counter was actually stopped */ + dev_dbg(dev, "checking for presence of RTC\n"); + ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf)); + if (ret < 0) + return ret; + + dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n", + rxbuf[0], rxbuf[1]); + if (!(rxbuf[0] & CTRL1_STOP)) + return -ENODEV; + + /* Start the counter */ + ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR); if (ret < 0) return ret; - pcf2123_delay_trec(); return 0; } @@ -217,13 +368,16 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) static const struct rtc_class_ops pcf2123_rtc_ops = { .read_time = pcf2123_rtc_read_time, .set_time = pcf2123_rtc_set_time, + .read_offset = pcf2123_read_offset, + .set_offset = pcf2123_set_offset, + }; static int pcf2123_probe(struct spi_device *spi) { struct rtc_device *rtc; + struct rtc_time tm; struct pcf2123_plat_data *pdata; - u8 txbuf[2], rxbuf[2]; int ret, i; pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data), @@ -232,56 +386,19 @@ static int pcf2123_probe(struct spi_device *spi) return -ENOMEM; spi->dev.platform_data = pdata; - /* Send a software reset command */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x58; - dev_dbg(&spi->dev, "resetting RTC (0x%02X 0x%02X)\n", - txbuf[0], txbuf[1]); - ret = spi_write(spi, txbuf, 2 * sizeof(u8)); - if (ret < 0) - goto kfree_exit; - pcf2123_delay_trec(); - - /* Stop the counter */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x20; - dev_dbg(&spi->dev, "stopping RTC (0x%02X 0x%02X)\n", - txbuf[0], txbuf[1]); - ret = spi_write(spi, txbuf, 2 * sizeof(u8)); - if (ret < 0) - goto kfree_exit; - pcf2123_delay_trec(); - - /* See if the counter was actually stopped */ - txbuf[0] = PCF2123_READ | PCF2123_REG_CTRL1; - dev_dbg(&spi->dev, "checking for presence of RTC (0x%02X)\n", - txbuf[0]); - ret = spi_write_then_read(spi, txbuf, 1 * sizeof(u8), - rxbuf, 2 * sizeof(u8)); - dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n", - rxbuf[0], rxbuf[1]); - if (ret < 0) - goto kfree_exit; - pcf2123_delay_trec(); - - if (!(rxbuf[0] & 0x20)) { - dev_err(&spi->dev, "chip not found\n"); - ret = -ENODEV; - goto kfree_exit; + ret = pcf2123_rtc_read_time(&spi->dev, &tm); + if (ret < 0) { + ret = pcf2123_reset(&spi->dev); + if (ret < 0) { + dev_err(&spi->dev, "chip not found\n"); + goto kfree_exit; + } } dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n"); dev_info(&spi->dev, "spiclk %u KHz.\n", (spi->max_speed_hz + 500) / 1000); - /* Start the counter */ - txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1; - txbuf[1] = 0x00; - ret = spi_write(spi, txbuf, sizeof(txbuf)); - if (ret < 0) - goto kfree_exit; - pcf2123_delay_trec(); - /* Finalize the initialization */ rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name, &pcf2123_rtc_ops, THIS_MODULE); diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 629bfdf8c..2bfdf638b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,12 +1,12 @@ /* - * An I2C driver for the NXP PCF2127 RTC + * An I2C and SPI driver for the NXP PCF2127/29 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato <r.cerrato@til-technologies.fr> * * based on the other drivers in this same directory. * - * http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf + * Datasheet: http://cache.nxp.com/documents/data_sheet/PCF2127.pdf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -14,11 +14,13 @@ */ #include <linux/i2c.h> +#include <linux/spi/spi.h> #include <linux/bcd.h> #include <linux/rtc.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/regmap.h> #define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */ #define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */ @@ -36,29 +38,30 @@ #define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ -static struct i2c_driver pcf2127_driver; - struct pcf2127 { struct rtc_device *rtc; + struct regmap *regmap; }; /* * In the routines that deal directly with the pcf2127 hardware, we use * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. */ -static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) +static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) { - unsigned char buf[10] = { PCF2127_REG_CTRL1 }; + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + unsigned char buf[10]; + int ret; - /* read registers */ - if (i2c_master_send(client, buf, 1) != 1 || - i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) { - dev_err(&client->dev, "%s: read error\n", __func__); - return -EIO; + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, buf, + sizeof(buf)); + if (ret) { + dev_err(dev, "%s: read error\n", __func__); + return ret; } if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF) - dev_info(&client->dev, + dev_info(dev, "low voltage detected, check/replace RTC battery.\n"); if (buf[PCF2127_REG_SC] & PCF2127_OSF) { @@ -66,12 +69,12 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) * no need clear the flag here, * it will be cleared once the new date is saved */ - dev_warn(&client->dev, + dev_warn(dev, "oscillator stop detected, date/time is not reliable\n"); return -EINVAL; } - dev_dbg(&client->dev, + dev_dbg(dev, "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, " "sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", @@ -91,7 +94,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) if (tm->tm_year < 70) tm->tm_year += 100; /* assume we are in 1970...2069 */ - dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, @@ -100,20 +103,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) return rtc_valid_tm(tm); } -static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) +static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) { - unsigned char buf[8]; + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + unsigned char buf[7]; int i = 0, err; - dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* start register address */ - buf[i++] = PCF2127_REG_SC; - /* hours, minutes and seconds */ buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */ buf[i++] = bin2bcd(tm->tm_min); @@ -128,11 +129,11 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[i++] = bin2bcd(tm->tm_year % 100); /* write register's data */ - err = i2c_master_send(client, buf, i); - if (err != i) { - dev_err(&client->dev, + err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); + if (err) { + dev_err(dev, "%s: err=%d", __func__, err); - return -EIO; + return err; } return 0; @@ -142,26 +143,17 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf2127_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct i2c_client *client = to_i2c_client(dev); - unsigned char buf = PCF2127_REG_CTRL3; + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); int touser; int ret; switch (cmd) { case RTC_VL_READ: - ret = i2c_master_send(client, &buf, 1); - if (!ret) - ret = -EIO; - if (ret < 0) - return ret; - - ret = i2c_master_recv(client, &buf, 1); - if (!ret) - ret = -EIO; - if (ret < 0) + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL3, &touser); + if (ret) return ret; - touser = buf & PCF2127_REG_CTRL3_BLF ? 1 : 0; + touser = touser & PCF2127_REG_CTRL3_BLF ? 1 : 0; if (copy_to_user((void __user *)arg, &touser, sizeof(int))) return -EFAULT; @@ -174,71 +166,270 @@ static int pcf2127_rtc_ioctl(struct device *dev, #define pcf2127_rtc_ioctl NULL #endif -static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - return pcf2127_get_datetime(to_i2c_client(dev), tm); -} - -static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - return pcf2127_set_datetime(to_i2c_client(dev), tm); -} - static const struct rtc_class_ops pcf2127_rtc_ops = { .ioctl = pcf2127_rtc_ioctl, .read_time = pcf2127_rtc_read_time, .set_time = pcf2127_rtc_set_time, }; -static int pcf2127_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pcf2127_probe(struct device *dev, struct regmap *regmap, + const char *name) { struct pcf2127 *pcf2127; - dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(dev, "%s\n", __func__); - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; - - pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127), - GFP_KERNEL); + pcf2127 = devm_kzalloc(dev, sizeof(*pcf2127), GFP_KERNEL); if (!pcf2127) return -ENOMEM; - i2c_set_clientdata(client, pcf2127); + pcf2127->regmap = regmap; + + dev_set_drvdata(dev, pcf2127); - pcf2127->rtc = devm_rtc_device_register(&client->dev, - pcf2127_driver.driver.name, - &pcf2127_rtc_ops, THIS_MODULE); + pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops, + THIS_MODULE); return PTR_ERR_OR_ZERO(pcf2127->rtc); } -static const struct i2c_device_id pcf2127_id[] = { - { "pcf2127", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, pcf2127_id); - #ifdef CONFIG_OF static const struct of_device_id pcf2127_of_match[] = { { .compatible = "nxp,pcf2127" }, + { .compatible = "nxp,pcf2129" }, {} }; MODULE_DEVICE_TABLE(of, pcf2127_of_match); #endif -static struct i2c_driver pcf2127_driver = { +#if IS_ENABLED(CONFIG_I2C) + +static int pcf2127_i2c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_master_send(client, data, count); + if (ret != count) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static int pcf2127_i2c_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) +{ + struct device *dev = context; + struct i2c_client *client = to_i2c_client(dev); + int ret; + void *buf; + + if (WARN_ON(reg_size != 1)) + return -EINVAL; + + buf = kmalloc(val_size + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf, reg, 1); + memcpy(buf + 1, val, val_size); + + ret = i2c_master_send(client, buf, val_size + 1); + if (ret != val_size + 1) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static int pcf2127_i2c_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct device *dev = context; + struct i2c_client *client = to_i2c_client(dev); + int ret; + + if (WARN_ON(reg_size != 1)) + return -EINVAL; + + ret = i2c_master_send(client, reg, 1); + if (ret != 1) + return ret < 0 ? ret : -EIO; + + ret = i2c_master_recv(client, val, val_size); + if (ret != val_size) + return ret < 0 ? ret : -EIO; + + return 0; +} + +/* + * The reason we need this custom regmap_bus instead of using regmap_init_i2c() + * is that the STOP condition is required between set register address and + * read register data when reading from registers. + */ +static const struct regmap_bus pcf2127_i2c_regmap = { + .write = pcf2127_i2c_write, + .gather_write = pcf2127_i2c_gather_write, + .read = pcf2127_i2c_read, +}; + +static struct i2c_driver pcf2127_i2c_driver; + +static int pcf2127_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + }; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap, + &client->dev, &config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "%s: regmap allocation failed: %ld\n", + __func__, PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return pcf2127_probe(&client->dev, regmap, + pcf2127_i2c_driver.driver.name); +} + +static const struct i2c_device_id pcf2127_i2c_id[] = { + { "pcf2127", 0 }, + { "pcf2129", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); + +static struct i2c_driver pcf2127_i2c_driver = { + .driver = { + .name = "rtc-pcf2127-i2c", + .of_match_table = of_match_ptr(pcf2127_of_match), + }, + .probe = pcf2127_i2c_probe, + .id_table = pcf2127_i2c_id, +}; + +static int pcf2127_i2c_register_driver(void) +{ + return i2c_add_driver(&pcf2127_i2c_driver); +} + +static void pcf2127_i2c_unregister_driver(void) +{ + i2c_del_driver(&pcf2127_i2c_driver); +} + +#else + +static int pcf2127_i2c_register_driver(void) +{ + return 0; +} + +static void pcf2127_i2c_unregister_driver(void) +{ +} + +#endif + +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static struct spi_driver pcf2127_spi_driver; + +static int pcf2127_spi_probe(struct spi_device *spi) +{ + static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = 0xa0, + .write_flag_mask = 0x20, + }; + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n", + __func__, PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name); +} + +static const struct spi_device_id pcf2127_spi_id[] = { + { "pcf2127", 0 }, + { "pcf2129", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); + +static struct spi_driver pcf2127_spi_driver = { .driver = { - .name = "rtc-pcf2127", + .name = "rtc-pcf2127-spi", .of_match_table = of_match_ptr(pcf2127_of_match), }, - .probe = pcf2127_probe, - .id_table = pcf2127_id, + .probe = pcf2127_spi_probe, + .id_table = pcf2127_spi_id, }; -module_i2c_driver(pcf2127_driver); +static int pcf2127_spi_register_driver(void) +{ + return spi_register_driver(&pcf2127_spi_driver); +} + +static void pcf2127_spi_unregister_driver(void) +{ + spi_unregister_driver(&pcf2127_spi_driver); +} + +#else + +static int pcf2127_spi_register_driver(void) +{ + return 0; +} + +static void pcf2127_spi_unregister_driver(void) +{ +} + +#endif + +static int __init pcf2127_init(void) +{ + int ret; + + ret = pcf2127_i2c_register_driver(); + if (ret) { + pr_err("Failed to register pcf2127 i2c driver: %d\n", ret); + return ret; + } + + ret = pcf2127_spi_register_driver(); + if (ret) { + pr_err("Failed to register pcf2127 spi driver: %d\n", ret); + pcf2127_i2c_unregister_driver(); + } + + return ret; +} +module_init(pcf2127_init) + +static void __exit pcf2127_exit(void) +{ + pcf2127_spi_unregister_driver(); + pcf2127_i2c_unregister_driver(); +} +module_exit(pcf2127_exit) MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>"); -MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); +MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 63334cbec..e8ddbb359 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -16,12 +16,12 @@ #include <linux/rtc.h> #include <linux/module.h> -#define DRV_VERSION "0.0.1" - #define PCF85063_REG_CTRL1 0x00 /* status */ +#define PCF85063_REG_CTRL1_STOP BIT(5) #define PCF85063_REG_CTRL2 0x01 #define PCF85063_REG_SC 0x04 /* datetime */ +#define PCF85063_REG_SC_OS 0x80 #define PCF85063_REG_MN 0x05 #define PCF85063_REG_HR 0x06 #define PCF85063_REG_DM 0x07 @@ -29,15 +29,31 @@ #define PCF85063_REG_MO 0x09 #define PCF85063_REG_YR 0x0A -#define PCF85063_MO_C 0x80 /* century */ - static struct i2c_driver pcf85063_driver; -struct pcf85063 { - struct rtc_device *rtc; - int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ - int voltage_low; /* indicates if a low_voltage was detected */ -}; +static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1) +{ + s32 ret; + + ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); + if (ret < 0) { + dev_err(&client->dev, "Failing to stop the clock\n"); + return -EIO; + } + + /* stop the clock */ + ret |= PCF85063_REG_CTRL1_STOP; + + ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&client->dev, "Failing to stop the clock\n"); + return -EIO; + } + + *ctrl1 = ret; + + return 0; +} /* * In the routines that deal directly with the pcf85063 hardware, we use @@ -45,81 +61,85 @@ struct pcf85063 { */ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) { - struct pcf85063 *pcf85063 = i2c_get_clientdata(client); - unsigned char buf[13] = { PCF85063_REG_CTRL1 }; - struct i2c_msg msgs[] = { - {/* setup read ptr */ - .addr = client->addr, - .len = 1, - .buf = buf - }, - {/* read status + date */ - .addr = client->addr, - .flags = I2C_M_RD, - .len = 13, - .buf = buf - }, - }; - - /* read registers */ - if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __func__); + int rc; + u8 regs[7]; + + /* + * while reading, the time/date registers are blocked and not updated + * anymore until the access is finished. To not lose a second + * event, the access must be finished within one second. So, read all + * time/date registers in one turn. + */ + rc = i2c_smbus_read_i2c_block_data(client, PCF85063_REG_SC, + sizeof(regs), regs); + if (rc != sizeof(regs)) { + dev_err(&client->dev, "date/time register read error\n"); return -EIO; } - tm->tm_sec = bcd2bin(buf[PCF85063_REG_SC] & 0x7F); - tm->tm_min = bcd2bin(buf[PCF85063_REG_MN] & 0x7F); - tm->tm_hour = bcd2bin(buf[PCF85063_REG_HR] & 0x3F); /* rtc hr 0-23 */ - tm->tm_mday = bcd2bin(buf[PCF85063_REG_DM] & 0x3F); - tm->tm_wday = buf[PCF85063_REG_DW] & 0x07; - tm->tm_mon = bcd2bin(buf[PCF85063_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = bcd2bin(buf[PCF85063_REG_YR]); + /* if the clock has lost its power it makes no sense to use its time */ + if (regs[0] & PCF85063_REG_SC_OS) { + dev_warn(&client->dev, "Power loss detected, invalid time\n"); + return -EINVAL; + } + + tm->tm_sec = bcd2bin(regs[0] & 0x7F); + tm->tm_min = bcd2bin(regs[1] & 0x7F); + tm->tm_hour = bcd2bin(regs[2] & 0x3F); /* rtc hr 0-23 */ + tm->tm_mday = bcd2bin(regs[3] & 0x3F); + tm->tm_wday = regs[4] & 0x07; + tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(regs[6]); if (tm->tm_year < 70) tm->tm_year += 100; /* assume we are in 1970...2069 */ - /* detect the polarity heuristically. see note above. */ - pcf85063->c_polarity = (buf[PCF85063_REG_MO] & PCF85063_MO_C) ? - (tm->tm_year >= 100) : (tm->tm_year < 100); return rtc_valid_tm(tm); } static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) { - int i = 0, err = 0; - unsigned char buf[11]; + int rc; + u8 regs[8]; - /* Control & status */ - buf[PCF85063_REG_CTRL1] = 0; - buf[PCF85063_REG_CTRL2] = 5; + /* + * to accurately set the time, reset the divider chain and keep it in + * reset state until all time/date registers are written + */ + rc = pcf85063_stop_clock(client, ®s[7]); + if (rc != 0) + return rc; /* hours, minutes and seconds */ - buf[PCF85063_REG_SC] = bin2bcd(tm->tm_sec) & 0x7F; + regs[0] = bin2bcd(tm->tm_sec) & 0x7F; /* clear OS flag */ - buf[PCF85063_REG_MN] = bin2bcd(tm->tm_min); - buf[PCF85063_REG_HR] = bin2bcd(tm->tm_hour); + regs[1] = bin2bcd(tm->tm_min); + regs[2] = bin2bcd(tm->tm_hour); /* Day of month, 1 - 31 */ - buf[PCF85063_REG_DM] = bin2bcd(tm->tm_mday); + regs[3] = bin2bcd(tm->tm_mday); /* Day, 0 - 6 */ - buf[PCF85063_REG_DW] = tm->tm_wday & 0x07; + regs[4] = tm->tm_wday & 0x07; /* month, 1 - 12 */ - buf[PCF85063_REG_MO] = bin2bcd(tm->tm_mon + 1); + regs[5] = bin2bcd(tm->tm_mon + 1); /* year and century */ - buf[PCF85063_REG_YR] = bin2bcd(tm->tm_year % 100); - - /* write register's data */ - for (i = 0; i < sizeof(buf); i++) { - unsigned char data[2] = { i, buf[i] }; - - err = i2c_master_send(client, data, sizeof(data)); - if (err != sizeof(data)) { - dev_err(&client->dev, "%s: err=%d addr=%02x, data=%02x\n", - __func__, err, data[0], data[1]); - return -EIO; - } + regs[6] = bin2bcd(tm->tm_year % 100); + + /* + * after all time/date registers are written, let the 'address auto + * increment' feature wrap around and write register CTRL1 to re-enable + * the clock divider chain again + */ + regs[7] &= ~PCF85063_REG_CTRL1_STOP; + + /* write all registers at once */ + rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC, + sizeof(regs), regs); + if (rc < 0) { + dev_err(&client->dev, "date/time register write error\n"); + return rc; } return 0; @@ -143,27 +163,18 @@ static const struct rtc_class_ops pcf85063_rtc_ops = { static int pcf85063_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pcf85063 *pcf85063; + struct rtc_device *rtc; dev_dbg(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063), - GFP_KERNEL); - if (!pcf85063) - return -ENOMEM; - - dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - - i2c_set_clientdata(client, pcf85063); - - pcf85063->rtc = devm_rtc_device_register(&client->dev, - pcf85063_driver.driver.name, - &pcf85063_rtc_ops, THIS_MODULE); + rtc = devm_rtc_device_register(&client->dev, + pcf85063_driver.driver.name, + &pcf85063_rtc_ops, THIS_MODULE); - return PTR_ERR_OR_ZERO(pcf85063->rtc); + return PTR_ERR_OR_ZERO(rtc); } static const struct i2c_device_id pcf85063_id[] = { @@ -194,4 +205,3 @@ module_i2c_driver(pcf85063_driver); MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>"); MODULE_DESCRIPTION("PCF85063 RTC driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 988566caa..28c48b3c1 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -178,28 +178,8 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) if (err < 0) return err; - if (regs[0] & REG_SECONDS_OS) { - /* - * If the oscillator was stopped, try to clear the flag. Upon - * power-up the flag is always set, but if we cannot clear it - * the oscillator isn't running properly for some reason. The - * sensible thing therefore is to return an error, signalling - * that the clock cannot be assumed to be correct. - */ - - regs[0] &= ~REG_SECONDS_OS; - - err = pcf8523_write(client, REG_SECONDS, regs[0]); - if (err < 0) - return err; - - err = pcf8523_read(client, REG_SECONDS, ®s[0]); - if (err < 0) - return err; - - if (regs[0] & REG_SECONDS_OS) - return -EAGAIN; - } + if (regs[0] & REG_SECONDS_OS) + return -EINVAL; tm->tm_sec = bcd2bin(regs[0] & 0x7f); tm->tm_min = bcd2bin(regs[1] & 0x7f); @@ -235,6 +215,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) return err; regs[0] = REG_SECONDS; + /* This will purposely overwrite REG_SECONDS_OS */ regs[1] = bin2bcd(tm->tm_sec); regs[2] = bin2bcd(tm->tm_min); regs[3] = bin2bcd(tm->tm_hour); diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c new file mode 100644 index 000000000..64e1e4578 --- /dev/null +++ b/drivers/rtc/rtc-pic32.c @@ -0,0 +1,411 @@ +/* + * PIC32 RTC driver + * + * Joshua Henderson <joshua.henderson@microchip.com> + * Copyright (C) 2016 Microchip Technology Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/rtc.h> +#include <linux/bcd.h> + +#include <asm/mach-pic32/pic32.h> + +#define PIC32_RTCCON 0x00 +#define PIC32_RTCCON_ON BIT(15) +#define PIC32_RTCCON_SIDL BIT(13) +#define PIC32_RTCCON_RTCCLKSEL (3 << 9) +#define PIC32_RTCCON_RTCCLKON BIT(6) +#define PIC32_RTCCON_RTCWREN BIT(3) +#define PIC32_RTCCON_RTCSYNC BIT(2) +#define PIC32_RTCCON_HALFSEC BIT(1) +#define PIC32_RTCCON_RTCOE BIT(0) + +#define PIC32_RTCALRM 0x10 +#define PIC32_RTCALRM_ALRMEN BIT(15) +#define PIC32_RTCALRM_CHIME BIT(14) +#define PIC32_RTCALRM_PIV BIT(13) +#define PIC32_RTCALRM_ALARMSYNC BIT(12) +#define PIC32_RTCALRM_AMASK 0x0F00 +#define PIC32_RTCALRM_ARPT 0xFF + +#define PIC32_RTCHOUR 0x23 +#define PIC32_RTCMIN 0x22 +#define PIC32_RTCSEC 0x21 +#define PIC32_RTCYEAR 0x33 +#define PIC32_RTCMON 0x32 +#define PIC32_RTCDAY 0x31 + +#define PIC32_ALRMTIME 0x40 +#define PIC32_ALRMDATE 0x50 + +#define PIC32_ALRMHOUR 0x43 +#define PIC32_ALRMMIN 0x42 +#define PIC32_ALRMSEC 0x41 +#define PIC32_ALRMYEAR 0x53 +#define PIC32_ALRMMON 0x52 +#define PIC32_ALRMDAY 0x51 + +struct pic32_rtc_dev { + struct rtc_device *rtc; + void __iomem *reg_base; + struct clk *clk; + spinlock_t alarm_lock; + int alarm_irq; + bool alarm_clk_enabled; +}; + +static void pic32_rtc_alarm_clk_enable(struct pic32_rtc_dev *pdata, + bool enable) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->alarm_lock, flags); + if (enable) { + if (!pdata->alarm_clk_enabled) { + clk_enable(pdata->clk); + pdata->alarm_clk_enabled = true; + } + } else { + if (pdata->alarm_clk_enabled) { + clk_disable(pdata->clk); + pdata->alarm_clk_enabled = false; + } + } + spin_unlock_irqrestore(&pdata->alarm_lock, flags); +} + +static irqreturn_t pic32_rtc_alarmirq(int irq, void *id) +{ + struct pic32_rtc_dev *pdata = (struct pic32_rtc_dev *)id; + + clk_enable(pdata->clk); + rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF); + clk_disable(pdata->clk); + + pic32_rtc_alarm_clk_enable(pdata, false); + + return IRQ_HANDLED; +} + +static int pic32_rtc_setaie(struct device *dev, unsigned int enabled) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + + clk_enable(pdata->clk); + + writel(PIC32_RTCALRM_ALRMEN, + base + (enabled ? PIC32_SET(PIC32_RTCALRM) : + PIC32_CLR(PIC32_RTCALRM))); + + clk_disable(pdata->clk); + + pic32_rtc_alarm_clk_enable(pdata, enabled); + + return 0; +} + +static int pic32_rtc_setfreq(struct device *dev, int freq) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + + clk_enable(pdata->clk); + + writel(PIC32_RTCALRM_AMASK, base + PIC32_CLR(PIC32_RTCALRM)); + writel(freq << 8, base + PIC32_SET(PIC32_RTCALRM)); + writel(PIC32_RTCALRM_CHIME, base + PIC32_SET(PIC32_RTCALRM)); + + clk_disable(pdata->clk); + + return 0; +} + +static int pic32_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + unsigned int tries = 0; + + clk_enable(pdata->clk); + + do { + rtc_tm->tm_hour = readb(base + PIC32_RTCHOUR); + rtc_tm->tm_min = readb(base + PIC32_RTCMIN); + rtc_tm->tm_mon = readb(base + PIC32_RTCMON); + rtc_tm->tm_mday = readb(base + PIC32_RTCDAY); + rtc_tm->tm_year = readb(base + PIC32_RTCYEAR); + rtc_tm->tm_sec = readb(base + PIC32_RTCSEC); + + /* + * The only way to work out whether the system was mid-update + * when we read it is to check the second counter, and if it + * is zero, then we re-try the entire read. + */ + tries += 1; + } while (rtc_tm->tm_sec == 0 && tries < 2); + + rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); + rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); + rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); + rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); + rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon) - 1; + rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); + + rtc_tm->tm_year += 100; + + dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, + rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); + + clk_disable(pdata->clk); + return rtc_valid_tm(rtc_tm); +} + +static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + int year = tm->tm_year - 100; + + dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + if (year < 0 || year >= 100) { + dev_err(dev, "rtc only supports 100 years\n"); + return -EINVAL; + } + + clk_enable(pdata->clk); + writeb(bin2bcd(tm->tm_sec), base + PIC32_RTCSEC); + writeb(bin2bcd(tm->tm_min), base + PIC32_RTCMIN); + writeb(bin2bcd(tm->tm_hour), base + PIC32_RTCHOUR); + writeb(bin2bcd(tm->tm_mday), base + PIC32_RTCDAY); + writeb(bin2bcd(tm->tm_mon + 1), base + PIC32_RTCMON); + writeb(bin2bcd(year), base + PIC32_RTCYEAR); + clk_disable(pdata->clk); + + return 0; +} + +static int pic32_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + struct rtc_time *alm_tm = &alrm->time; + void __iomem *base = pdata->reg_base; + unsigned int alm_en; + + clk_enable(pdata->clk); + alm_tm->tm_sec = readb(base + PIC32_ALRMSEC); + alm_tm->tm_min = readb(base + PIC32_ALRMMIN); + alm_tm->tm_hour = readb(base + PIC32_ALRMHOUR); + alm_tm->tm_mon = readb(base + PIC32_ALRMMON); + alm_tm->tm_mday = readb(base + PIC32_ALRMDAY); + alm_tm->tm_year = readb(base + PIC32_ALRMYEAR); + + alm_en = readb(base + PIC32_RTCALRM); + + alrm->enabled = (alm_en & PIC32_RTCALRM_ALRMEN) ? 1 : 0; + + dev_dbg(dev, "getalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", + alm_en, + 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, + alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); + + alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); + alm_tm->tm_min = bcd2bin(alm_tm->tm_min); + alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); + alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); + alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon) - 1; + alm_tm->tm_year = bcd2bin(alm_tm->tm_year); + + clk_disable(pdata->clk); + return 0; +} + +static int pic32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + void __iomem *base = pdata->reg_base; + + clk_enable(pdata->clk); + dev_dbg(dev, "setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", + alrm->enabled, + 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + writel(0x00, base + PIC32_ALRMTIME); + writel(0x00, base + PIC32_ALRMDATE); + + pic32_rtc_setaie(dev, alrm->enabled); + + clk_disable(pdata->clk); + return 0; +} + +static int pic32_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct pic32_rtc_dev *pdata = dev_get_drvdata(dev); + void __iomem *base = pdata->reg_base; + unsigned int repeat; + + clk_enable(pdata->clk); + + repeat = readw(base + PIC32_RTCALRM); + repeat &= PIC32_RTCALRM_ARPT; + seq_printf(seq, "periodic_IRQ\t: %s\n", repeat ? "yes" : "no"); + + clk_disable(pdata->clk); + return 0; +} + +static const struct rtc_class_ops pic32_rtcops = { + .read_time = pic32_rtc_gettime, + .set_time = pic32_rtc_settime, + .read_alarm = pic32_rtc_getalarm, + .set_alarm = pic32_rtc_setalarm, + .proc = pic32_rtc_proc, + .alarm_irq_enable = pic32_rtc_setaie, +}; + +static void pic32_rtc_enable(struct pic32_rtc_dev *pdata, int en) +{ + void __iomem *base = pdata->reg_base; + + if (!base) + return; + + clk_enable(pdata->clk); + if (!en) { + writel(PIC32_RTCCON_ON, base + PIC32_CLR(PIC32_RTCCON)); + } else { + pic32_syskey_unlock(); + + writel(PIC32_RTCCON_RTCWREN, base + PIC32_SET(PIC32_RTCCON)); + writel(3 << 9, base + PIC32_CLR(PIC32_RTCCON)); + + if (!(readl(base + PIC32_RTCCON) & PIC32_RTCCON_ON)) + writel(PIC32_RTCCON_ON, base + PIC32_SET(PIC32_RTCCON)); + } + clk_disable(pdata->clk); +} + +static int pic32_rtc_remove(struct platform_device *pdev) +{ + struct pic32_rtc_dev *pdata = platform_get_drvdata(pdev); + + pic32_rtc_setaie(&pdev->dev, 0); + clk_unprepare(pdata->clk); + pdata->clk = NULL; + + return 0; +} + +static int pic32_rtc_probe(struct platform_device *pdev) +{ + struct pic32_rtc_dev *pdata; + struct resource *res; + int ret; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + platform_set_drvdata(pdev, pdata); + + pdata->alarm_irq = platform_get_irq(pdev, 0); + if (pdata->alarm_irq < 0) { + dev_err(&pdev->dev, "no irq for alarm\n"); + return pdata->alarm_irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pdata->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->reg_base)) + return PTR_ERR(pdata->reg_base); + + pdata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pdata->clk)) { + dev_err(&pdev->dev, "failed to find rtc clock source\n"); + ret = PTR_ERR(pdata->clk); + pdata->clk = NULL; + return ret; + } + + spin_lock_init(&pdata->alarm_lock); + + clk_prepare_enable(pdata->clk); + + pic32_rtc_enable(pdata, 1); + + device_init_wakeup(&pdev->dev, 1); + + pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &pic32_rtcops, + THIS_MODULE); + if (IS_ERR(pdata->rtc)) { + ret = PTR_ERR(pdata->rtc); + goto err_nortc; + } + + pdata->rtc->max_user_freq = 128; + + pic32_rtc_setfreq(&pdev->dev, 1); + ret = devm_request_irq(&pdev->dev, pdata->alarm_irq, + pic32_rtc_alarmirq, 0, + dev_name(&pdev->dev), pdata); + if (ret) { + dev_err(&pdev->dev, + "IRQ %d error %d\n", pdata->alarm_irq, ret); + goto err_nortc; + } + + clk_disable(pdata->clk); + + return 0; + +err_nortc: + pic32_rtc_enable(pdata, 0); + clk_disable_unprepare(pdata->clk); + + return ret; +} + +static const struct of_device_id pic32_rtc_dt_ids[] = { + { .compatible = "microchip,pic32mzda-rtc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids); + +static struct platform_driver pic32_rtc_driver = { + .probe = pic32_rtc_probe, + .remove = pic32_rtc_remove, + .driver = { + .name = "pic32-rtc", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pic32_rtc_dt_ids), + }, +}; +module_platform_driver(pic32_rtc_driver); + +MODULE_DESCRIPTION("Microchip PIC32 RTC Driver"); +MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index e9ac5a43b..d0cbf0804 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -1,7 +1,8 @@ /* - * Micro Crystal RV-3029C2 rtc class driver + * Micro Crystal RV-3029 rtc class driver * * Author: Gregory Hermant <gregory.hermant@calao-systems.com> + * Michael Buesch <m@bues.ch> * * based on previously existing rtc class drivers * @@ -9,89 +10,120 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * NOTE: Currently this driver only supports the bare minimum for read - * and write the RTC and alarms. The extra features provided by this chip - * (trickle charger, eeprom, T° compensation) are unavailable. */ #include <linux/module.h> #include <linux/i2c.h> #include <linux/bcd.h> #include <linux/rtc.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> + /* Register map */ /* control section */ -#define RV3029C2_ONOFF_CTRL 0x00 -#define RV3029C2_IRQ_CTRL 0x01 -#define RV3029C2_IRQ_CTRL_AIE (1 << 0) -#define RV3029C2_IRQ_FLAGS 0x02 -#define RV3029C2_IRQ_FLAGS_AF (1 << 0) -#define RV3029C2_STATUS 0x03 -#define RV3029C2_STATUS_VLOW1 (1 << 2) -#define RV3029C2_STATUS_VLOW2 (1 << 3) -#define RV3029C2_STATUS_SR (1 << 4) -#define RV3029C2_STATUS_PON (1 << 5) -#define RV3029C2_STATUS_EEBUSY (1 << 7) -#define RV3029C2_RST_CTRL 0x04 -#define RV3029C2_CONTROL_SECTION_LEN 0x05 +#define RV3029_ONOFF_CTRL 0x00 +#define RV3029_ONOFF_CTRL_WE BIT(0) +#define RV3029_ONOFF_CTRL_TE BIT(1) +#define RV3029_ONOFF_CTRL_TAR BIT(2) +#define RV3029_ONOFF_CTRL_EERE BIT(3) +#define RV3029_ONOFF_CTRL_SRON BIT(4) +#define RV3029_ONOFF_CTRL_TD0 BIT(5) +#define RV3029_ONOFF_CTRL_TD1 BIT(6) +#define RV3029_ONOFF_CTRL_CLKINT BIT(7) +#define RV3029_IRQ_CTRL 0x01 +#define RV3029_IRQ_CTRL_AIE BIT(0) +#define RV3029_IRQ_CTRL_TIE BIT(1) +#define RV3029_IRQ_CTRL_V1IE BIT(2) +#define RV3029_IRQ_CTRL_V2IE BIT(3) +#define RV3029_IRQ_CTRL_SRIE BIT(4) +#define RV3029_IRQ_FLAGS 0x02 +#define RV3029_IRQ_FLAGS_AF BIT(0) +#define RV3029_IRQ_FLAGS_TF BIT(1) +#define RV3029_IRQ_FLAGS_V1IF BIT(2) +#define RV3029_IRQ_FLAGS_V2IF BIT(3) +#define RV3029_IRQ_FLAGS_SRF BIT(4) +#define RV3029_STATUS 0x03 +#define RV3029_STATUS_VLOW1 BIT(2) +#define RV3029_STATUS_VLOW2 BIT(3) +#define RV3029_STATUS_SR BIT(4) +#define RV3029_STATUS_PON BIT(5) +#define RV3029_STATUS_EEBUSY BIT(7) +#define RV3029_RST_CTRL 0x04 +#define RV3029_RST_CTRL_SYSR BIT(4) +#define RV3029_CONTROL_SECTION_LEN 0x05 /* watch section */ -#define RV3029C2_W_SEC 0x08 -#define RV3029C2_W_MINUTES 0x09 -#define RV3029C2_W_HOURS 0x0A -#define RV3029C2_REG_HR_12_24 (1<<6) /* 24h/12h mode */ -#define RV3029C2_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ -#define RV3029C2_W_DATE 0x0B -#define RV3029C2_W_DAYS 0x0C -#define RV3029C2_W_MONTHS 0x0D -#define RV3029C2_W_YEARS 0x0E -#define RV3029C2_WATCH_SECTION_LEN 0x07 +#define RV3029_W_SEC 0x08 +#define RV3029_W_MINUTES 0x09 +#define RV3029_W_HOURS 0x0A +#define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */ +#define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */ +#define RV3029_W_DATE 0x0B +#define RV3029_W_DAYS 0x0C +#define RV3029_W_MONTHS 0x0D +#define RV3029_W_YEARS 0x0E +#define RV3029_WATCH_SECTION_LEN 0x07 /* alarm section */ -#define RV3029C2_A_SC 0x10 -#define RV3029C2_A_MN 0x11 -#define RV3029C2_A_HR 0x12 -#define RV3029C2_A_DT 0x13 -#define RV3029C2_A_DW 0x14 -#define RV3029C2_A_MO 0x15 -#define RV3029C2_A_YR 0x16 -#define RV3029C2_ALARM_SECTION_LEN 0x07 +#define RV3029_A_SC 0x10 +#define RV3029_A_MN 0x11 +#define RV3029_A_HR 0x12 +#define RV3029_A_DT 0x13 +#define RV3029_A_DW 0x14 +#define RV3029_A_MO 0x15 +#define RV3029_A_YR 0x16 +#define RV3029_ALARM_SECTION_LEN 0x07 /* timer section */ -#define RV3029C2_TIMER_LOW 0x18 -#define RV3029C2_TIMER_HIGH 0x19 +#define RV3029_TIMER_LOW 0x18 +#define RV3029_TIMER_HIGH 0x19 /* temperature section */ -#define RV3029C2_TEMP_PAGE 0x20 +#define RV3029_TEMP_PAGE 0x20 /* eeprom data section */ -#define RV3029C2_E2P_EEDATA1 0x28 -#define RV3029C2_E2P_EEDATA2 0x29 +#define RV3029_E2P_EEDATA1 0x28 +#define RV3029_E2P_EEDATA2 0x29 +#define RV3029_E2PDATA_SECTION_LEN 0x02 /* eeprom control section */ -#define RV3029C2_CONTROL_E2P_EECTRL 0x30 -#define RV3029C2_TRICKLE_1K (1<<0) /* 1K resistance */ -#define RV3029C2_TRICKLE_5K (1<<1) /* 5K resistance */ -#define RV3029C2_TRICKLE_20K (1<<2) /* 20K resistance */ -#define RV3029C2_TRICKLE_80K (1<<3) /* 80K resistance */ -#define RV3029C2_CONTROL_E2P_XTALOFFSET 0x31 -#define RV3029C2_CONTROL_E2P_QCOEF 0x32 -#define RV3029C2_CONTROL_E2P_TURNOVER 0x33 +#define RV3029_CONTROL_E2P_EECTRL 0x30 +#define RV3029_EECTRL_THP BIT(0) /* temp scan interval */ +#define RV3029_EECTRL_THE BIT(1) /* thermometer enable */ +#define RV3029_EECTRL_FD0 BIT(2) /* CLKOUT */ +#define RV3029_EECTRL_FD1 BIT(3) /* CLKOUT */ +#define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */ +#define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */ +#define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */ +#define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */ +#define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\ + RV3029_TRICKLE_5K |\ + RV3029_TRICKLE_20K |\ + RV3029_TRICKLE_80K) +#define RV3029_TRICKLE_SHIFT 4 +#define RV3029_CONTROL_E2P_XOFFS 0x31 /* XTAL offset */ +#define RV3029_CONTROL_E2P_XOFFS_SIGN BIT(7) /* Sign: 1->pos, 0->neg */ +#define RV3029_CONTROL_E2P_QCOEF 0x32 /* XTAL temp drift coef */ +#define RV3029_CONTROL_E2P_TURNOVER 0x33 /* XTAL turnover temp (in *C) */ +#define RV3029_CONTROL_E2P_TOV_MASK 0x3F /* XTAL turnover temp mask */ /* user ram section */ -#define RV3029C2_USR1_RAM_PAGE 0x38 -#define RV3029C2_USR1_SECTION_LEN 0x04 -#define RV3029C2_USR2_RAM_PAGE 0x3C -#define RV3029C2_USR2_SECTION_LEN 0x04 +#define RV3029_USR1_RAM_PAGE 0x38 +#define RV3029_USR1_SECTION_LEN 0x04 +#define RV3029_USR2_RAM_PAGE 0x3C +#define RV3029_USR2_SECTION_LEN 0x04 static int -rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, - unsigned len) +rv3029_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, + unsigned len) { int ret; - if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || - (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) + if ((reg > RV3029_USR1_RAM_PAGE + 7) || + (reg + len > RV3029_USR1_RAM_PAGE + 8)) return -EINVAL; ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf); @@ -103,20 +135,38 @@ rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf, } static int -rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[], - unsigned len) +rv3029_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[], + unsigned len) { - if ((reg > RV3029C2_USR1_RAM_PAGE + 7) || - (reg + len > RV3029C2_USR1_RAM_PAGE + 8)) + if ((reg > RV3029_USR1_RAM_PAGE + 7) || + (reg + len > RV3029_USR1_RAM_PAGE + 8)) return -EINVAL; return i2c_smbus_write_i2c_block_data(client, reg, len, buf); } static int -rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf) +rv3029_i2c_update_bits(struct i2c_client *client, u8 reg, u8 mask, u8 set) +{ + u8 buf; + int ret; + + ret = rv3029_i2c_read_regs(client, reg, &buf, 1); + if (ret < 0) + return ret; + buf &= ~mask; + buf |= set & mask; + ret = rv3029_i2c_write_regs(client, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + +static int +rv3029_i2c_get_sr(struct i2c_client *client, u8 *buf) { - int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1); + int ret = rv3029_i2c_read_regs(client, RV3029_STATUS, buf, 1); if (ret < 0) return -EIO; @@ -125,83 +175,224 @@ rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf) } static int -rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val) +rv3029_i2c_set_sr(struct i2c_client *client, u8 val) { u8 buf[1]; int sr; buf[0] = val; - sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1); + sr = rv3029_i2c_write_regs(client, RV3029_STATUS, buf, 1); dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); if (sr < 0) return -EIO; return 0; } +static int rv3029_eeprom_busywait(struct i2c_client *client) +{ + int i, ret; + u8 sr; + + for (i = 100; i > 0; i--) { + ret = rv3029_i2c_get_sr(client, &sr); + if (ret < 0) + break; + if (!(sr & RV3029_STATUS_EEBUSY)) + break; + usleep_range(1000, 10000); + } + if (i <= 0) { + dev_err(&client->dev, "EEPROM busy wait timeout.\n"); + return -ETIMEDOUT; + } + + return ret; +} + +static int rv3029_eeprom_exit(struct i2c_client *client) +{ + /* Re-enable eeprom refresh */ + return rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL, + RV3029_ONOFF_CTRL_EERE, + RV3029_ONOFF_CTRL_EERE); +} + +static int rv3029_eeprom_enter(struct i2c_client *client) +{ + int ret; + u8 sr; + + /* Check whether we are in the allowed voltage range. */ + ret = rv3029_i2c_get_sr(client, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + /* We clear the bits and retry once just in case + * we had a brown out in early startup. + */ + sr &= ~RV3029_STATUS_VLOW1; + sr &= ~RV3029_STATUS_VLOW2; + ret = rv3029_i2c_set_sr(client, sr); + if (ret < 0) + return ret; + usleep_range(1000, 10000); + ret = rv3029_i2c_get_sr(client, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + dev_err(&client->dev, + "Supply voltage is too low to safely access the EEPROM.\n"); + return -ENODEV; + } + } + + /* Disable eeprom refresh. */ + ret = rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL, + RV3029_ONOFF_CTRL_EERE, 0); + if (ret < 0) + return ret; + + /* Wait for any previous eeprom accesses to finish. */ + ret = rv3029_eeprom_busywait(client); + if (ret < 0) + rv3029_eeprom_exit(client); + + return ret; +} + +static int rv3029_eeprom_read(struct i2c_client *client, u8 reg, + u8 buf[], size_t len) +{ + int ret, err; + + err = rv3029_eeprom_enter(client); + if (err < 0) + return err; + + ret = rv3029_i2c_read_regs(client, reg, buf, len); + + err = rv3029_eeprom_exit(client); + if (err < 0) + return err; + + return ret; +} + +static int rv3029_eeprom_write(struct i2c_client *client, u8 reg, + u8 const buf[], size_t len) +{ + int ret, err; + size_t i; + u8 tmp; + + err = rv3029_eeprom_enter(client); + if (err < 0) + return err; + + for (i = 0; i < len; i++, reg++) { + ret = rv3029_i2c_read_regs(client, reg, &tmp, 1); + if (ret < 0) + break; + if (tmp != buf[i]) { + ret = rv3029_i2c_write_regs(client, reg, &buf[i], 1); + if (ret < 0) + break; + } + ret = rv3029_eeprom_busywait(client); + if (ret < 0) + break; + } + + err = rv3029_eeprom_exit(client); + if (err < 0) + return err; + + return ret; +} + +static int rv3029_eeprom_update_bits(struct i2c_client *client, + u8 reg, u8 mask, u8 set) +{ + u8 buf; + int ret; + + ret = rv3029_eeprom_read(client, reg, &buf, 1); + if (ret < 0) + return ret; + buf &= ~mask; + buf |= set & mask; + ret = rv3029_eeprom_write(client, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + static int -rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) +rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) { u8 buf[1]; int ret; - u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, }; + u8 regs[RV3029_WATCH_SECTION_LEN] = { 0, }; - ret = rv3029c2_i2c_get_sr(client, buf); + ret = rv3029_i2c_get_sr(client, buf); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return -EIO; } - ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs, - RV3029C2_WATCH_SECTION_LEN); + ret = rv3029_i2c_read_regs(client, RV3029_W_SEC, regs, + RV3029_WATCH_SECTION_LEN); if (ret < 0) { dev_err(&client->dev, "%s: reading RTC section failed\n", __func__); return ret; } - tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]); - tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]); + tm->tm_sec = bcd2bin(regs[RV3029_W_SEC-RV3029_W_SEC]); + tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES-RV3029_W_SEC]); /* HR field has a more complex interpretation */ { - const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC]; - if (_hr & RV3029C2_REG_HR_12_24) { + const u8 _hr = regs[RV3029_W_HOURS-RV3029_W_SEC]; + + if (_hr & RV3029_REG_HR_12_24) { /* 12h format */ tm->tm_hour = bcd2bin(_hr & 0x1f); - if (_hr & RV3029C2_REG_HR_PM) /* PM flag set */ + if (_hr & RV3029_REG_HR_PM) /* PM flag set */ tm->tm_hour += 12; } else /* 24h format */ tm->tm_hour = bcd2bin(_hr & 0x3f); } - tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]); - tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1; - tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100; - tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1; + tm->tm_mday = bcd2bin(regs[RV3029_W_DATE-RV3029_W_SEC]); + tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS-RV3029_W_SEC]) - 1; + tm->tm_year = bcd2bin(regs[RV3029_W_YEARS-RV3029_W_SEC]) + 100; + tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS-RV3029_W_SEC]) - 1; return 0; } -static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int rv3029_rtc_read_time(struct device *dev, struct rtc_time *tm) { - return rv3029c2_i2c_read_time(to_i2c_client(dev), tm); + return rv3029_i2c_read_time(to_i2c_client(dev), tm); } static int -rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) +rv3029_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; int ret; u8 regs[8]; - ret = rv3029c2_i2c_get_sr(client, regs); + ret = rv3029_i2c_get_sr(client, regs); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return -EIO; } - ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs, - RV3029C2_ALARM_SECTION_LEN); + ret = rv3029_i2c_read_regs(client, RV3029_A_SC, regs, + RV3029_ALARM_SECTION_LEN); if (ret < 0) { dev_err(&client->dev, "%s: reading alarm section failed\n", @@ -209,51 +400,42 @@ rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) return ret; } - tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f); - tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f); - tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f); - tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f); - tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1; - tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100; - tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1; + tm->tm_sec = bcd2bin(regs[RV3029_A_SC-RV3029_A_SC] & 0x7f); + tm->tm_min = bcd2bin(regs[RV3029_A_MN-RV3029_A_SC] & 0x7f); + tm->tm_hour = bcd2bin(regs[RV3029_A_HR-RV3029_A_SC] & 0x3f); + tm->tm_mday = bcd2bin(regs[RV3029_A_DT-RV3029_A_SC] & 0x3f); + tm->tm_mon = bcd2bin(regs[RV3029_A_MO-RV3029_A_SC] & 0x1f) - 1; + tm->tm_year = bcd2bin(regs[RV3029_A_YR-RV3029_A_SC] & 0x7f) + 100; + tm->tm_wday = bcd2bin(regs[RV3029_A_DW-RV3029_A_SC] & 0x07) - 1; return 0; } static int -rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +rv3029_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm); + return rv3029_i2c_read_alarm(to_i2c_client(dev), alarm); } -static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client, +static int rv3029_rtc_i2c_alarm_set_irq(struct i2c_client *client, int enable) { int ret; - u8 buf[1]; - - /* enable AIE irq */ - ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1); - if (ret < 0) { - dev_err(&client->dev, "can't read INT reg\n"); - return ret; - } - if (enable) - buf[0] |= RV3029C2_IRQ_CTRL_AIE; - else - buf[0] &= ~RV3029C2_IRQ_CTRL_AIE; - ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1); + /* enable/disable AIE irq */ + ret = rv3029_i2c_update_bits(client, RV3029_IRQ_CTRL, + RV3029_IRQ_CTRL_AIE, + (enable ? RV3029_IRQ_CTRL_AIE : 0)); if (ret < 0) { - dev_err(&client->dev, "can't set INT reg\n"); + dev_err(&client->dev, "can't update INT reg\n"); return ret; } return 0; } -static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, - struct rtc_wkalrm *alarm) +static int rv3029_rtc_i2c_set_alarm(struct i2c_client *client, + struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; int ret; @@ -267,50 +449,41 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, if (tm->tm_year < 100) return -EINVAL; - ret = rv3029c2_i2c_get_sr(client, regs); + ret = rv3029_i2c_get_sr(client, regs); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return -EIO; } - regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f); - regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f); - regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f); - regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f); - regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1); - regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1); - regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100); - - ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs, - RV3029C2_ALARM_SECTION_LEN); + regs[RV3029_A_SC-RV3029_A_SC] = bin2bcd(tm->tm_sec & 0x7f); + regs[RV3029_A_MN-RV3029_A_SC] = bin2bcd(tm->tm_min & 0x7f); + regs[RV3029_A_HR-RV3029_A_SC] = bin2bcd(tm->tm_hour & 0x3f); + regs[RV3029_A_DT-RV3029_A_SC] = bin2bcd(tm->tm_mday & 0x3f); + regs[RV3029_A_MO-RV3029_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1); + regs[RV3029_A_DW-RV3029_A_SC] = bin2bcd((tm->tm_wday & 7) - 1); + regs[RV3029_A_YR-RV3029_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100); + + ret = rv3029_i2c_write_regs(client, RV3029_A_SC, regs, + RV3029_ALARM_SECTION_LEN); if (ret < 0) return ret; if (alarm->enabled) { - u8 buf[1]; - /* clear AF flag */ - ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS, - buf, 1); - if (ret < 0) { - dev_err(&client->dev, "can't read alarm flag\n"); - return ret; - } - buf[0] &= ~RV3029C2_IRQ_FLAGS_AF; - ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS, - buf, 1); + ret = rv3029_i2c_update_bits(client, RV3029_IRQ_FLAGS, + RV3029_IRQ_FLAGS_AF, 0); if (ret < 0) { - dev_err(&client->dev, "can't set alarm flag\n"); + dev_err(&client->dev, "can't clear alarm flag\n"); return ret; } /* enable AIE irq */ - ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1); + ret = rv3029_rtc_i2c_alarm_set_irq(client, 1); if (ret) return ret; dev_dbg(&client->dev, "alarm IRQ armed\n"); } else { /* disable AIE irq */ - ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 0); + ret = rv3029_rtc_i2c_alarm_set_irq(client, 0); if (ret) return ret; @@ -320,13 +493,13 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client, return 0; } -static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +static int rv3029_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm); + return rv3029_rtc_i2c_set_alarm(to_i2c_client(dev), alarm); } static int -rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) +rv3029_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) { u8 regs[8]; int ret; @@ -339,26 +512,26 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) if (tm->tm_year < 100) return -EINVAL; - regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec); - regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min); - regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour); - regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday); - regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1); - regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1); - regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100); + regs[RV3029_W_SEC-RV3029_W_SEC] = bin2bcd(tm->tm_sec); + regs[RV3029_W_MINUTES-RV3029_W_SEC] = bin2bcd(tm->tm_min); + regs[RV3029_W_HOURS-RV3029_W_SEC] = bin2bcd(tm->tm_hour); + regs[RV3029_W_DATE-RV3029_W_SEC] = bin2bcd(tm->tm_mday); + regs[RV3029_W_MONTHS-RV3029_W_SEC] = bin2bcd(tm->tm_mon+1); + regs[RV3029_W_DAYS-RV3029_W_SEC] = bin2bcd((tm->tm_wday & 7)+1); + regs[RV3029_W_YEARS-RV3029_W_SEC] = bin2bcd(tm->tm_year - 100); - ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs, - RV3029C2_WATCH_SECTION_LEN); + ret = rv3029_i2c_write_regs(client, RV3029_W_SEC, regs, + RV3029_WATCH_SECTION_LEN); if (ret < 0) return ret; - ret = rv3029c2_i2c_get_sr(client, regs); + ret = rv3029_i2c_get_sr(client, regs); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return ret; } /* clear PON bit */ - ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON)); + ret = rv3029_i2c_set_sr(client, (regs[0] & ~RV3029_STATUS_PON)); if (ret < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return ret; @@ -367,26 +540,238 @@ rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm) return 0; } -static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm) +static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm) { - return rv3029c2_i2c_set_time(to_i2c_client(dev), tm); + return rv3029_i2c_set_time(to_i2c_client(dev), tm); } -static const struct rtc_class_ops rv3029c2_rtc_ops = { - .read_time = rv3029c2_rtc_read_time, - .set_time = rv3029c2_rtc_set_time, - .read_alarm = rv3029c2_rtc_read_alarm, - .set_alarm = rv3029c2_rtc_set_alarm, +static const struct rv3029_trickle_tab_elem { + u32 r; /* resistance in ohms */ + u8 conf; /* trickle config bits */ +} rv3029_trickle_tab[] = { + { + .r = 1076, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 1091, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K, + }, { + .r = 1137, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_80K, + }, { + .r = 1154, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K, + }, { + .r = 1371, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 1395, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K, + }, { + .r = 1472, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K, + }, { + .r = 1500, + .conf = RV3029_TRICKLE_1K, + }, { + .r = 3810, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 4000, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K, + }, { + .r = 4706, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K, + }, { + .r = 5000, + .conf = RV3029_TRICKLE_5K, + }, { + .r = 16000, + .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 20000, + .conf = RV3029_TRICKLE_20K, + }, { + .r = 80000, + .conf = RV3029_TRICKLE_80K, + }, }; -static struct i2c_device_id rv3029c2_id[] = { +static void rv3029_trickle_config(struct i2c_client *client) +{ + struct device_node *of_node = client->dev.of_node; + const struct rv3029_trickle_tab_elem *elem; + int i, err; + u32 ohms; + u8 trickle_set_bits; + + if (!of_node) + return; + + /* Configure the trickle charger. */ + err = of_property_read_u32(of_node, "trickle-resistor-ohms", &ohms); + if (err) { + /* Disable trickle charger. */ + trickle_set_bits = 0; + } else { + /* Enable trickle charger. */ + for (i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) { + elem = &rv3029_trickle_tab[i]; + if (elem->r >= ohms) + break; + } + trickle_set_bits = elem->conf; + dev_info(&client->dev, + "Trickle charger enabled at %d ohms resistance.\n", + elem->r); + } + err = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL, + RV3029_TRICKLE_MASK, + trickle_set_bits); + if (err < 0) { + dev_err(&client->dev, + "Failed to update trickle charger config\n"); + } +} + +#ifdef CONFIG_RTC_DRV_RV3029_HWMON + +static int rv3029_read_temp(struct i2c_client *client, int *temp_mC) +{ + int ret; + u8 temp; + + ret = rv3029_i2c_read_regs(client, RV3029_TEMP_PAGE, &temp, 1); + if (ret < 0) + return ret; + + *temp_mC = ((int)temp - 60) * 1000; + + return 0; +} + +static ssize_t rv3029_hwmon_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = dev_get_drvdata(dev); + int ret, temp_mC; + + ret = rv3029_read_temp(client, &temp_mC); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", temp_mC); +} + +static ssize_t rv3029_hwmon_set_update_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct i2c_client *client = dev_get_drvdata(dev); + unsigned long interval_ms; + int ret; + u8 th_set_bits = 0; + + ret = kstrtoul(buf, 10, &interval_ms); + if (ret < 0) + return ret; + + if (interval_ms != 0) { + th_set_bits |= RV3029_EECTRL_THE; + if (interval_ms >= 16000) + th_set_bits |= RV3029_EECTRL_THP; + } + ret = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL, + RV3029_EECTRL_THE | RV3029_EECTRL_THP, + th_set_bits); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t rv3029_hwmon_show_update_interval(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = dev_get_drvdata(dev); + int ret, interval_ms; + u8 eectrl; + + ret = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL, + &eectrl, 1); + if (ret < 0) + return ret; + + if (eectrl & RV3029_EECTRL_THE) { + if (eectrl & RV3029_EECTRL_THP) + interval_ms = 16000; + else + interval_ms = 1000; + } else { + interval_ms = 0; + } + + return sprintf(buf, "%d\n", interval_ms); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, rv3029_hwmon_show_temp, + NULL, 0); +static SENSOR_DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, + rv3029_hwmon_show_update_interval, + rv3029_hwmon_set_update_interval, 0); + +static struct attribute *rv3029_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_update_interval.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(rv3029_hwmon); + +static void rv3029_hwmon_register(struct i2c_client *client) +{ + struct device *hwmon_dev; + + hwmon_dev = devm_hwmon_device_register_with_groups( + &client->dev, client->name, client, rv3029_hwmon_groups); + if (IS_ERR(hwmon_dev)) { + dev_warn(&client->dev, + "unable to register hwmon device %ld\n", + PTR_ERR(hwmon_dev)); + } +} + +#else /* CONFIG_RTC_DRV_RV3029_HWMON */ + +static void rv3029_hwmon_register(struct i2c_client *client) +{ +} + +#endif /* CONFIG_RTC_DRV_RV3029_HWMON */ + +static const struct rtc_class_ops rv3029_rtc_ops = { + .read_time = rv3029_rtc_read_time, + .set_time = rv3029_rtc_set_time, + .read_alarm = rv3029_rtc_read_alarm, + .set_alarm = rv3029_rtc_set_alarm, +}; + +static struct i2c_device_id rv3029_id[] = { + { "rv3029", 0 }, { "rv3029c2", 0 }, { } }; -MODULE_DEVICE_TABLE(i2c, rv3029c2_id); +MODULE_DEVICE_TABLE(i2c, rv3029_id); -static int rv3029c2_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int rv3029_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct rtc_device *rtc; int rc = 0; @@ -395,14 +780,17 @@ static int rv3029c2_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL)) return -ENODEV; - rc = rv3029c2_i2c_get_sr(client, buf); + rc = rv3029_i2c_get_sr(client, buf); if (rc < 0) { dev_err(&client->dev, "reading status failed\n"); return rc; } + rv3029_trickle_config(client); + rv3029_hwmon_register(client); + rtc = devm_rtc_device_register(&client->dev, client->name, - &rv3029c2_rtc_ops, THIS_MODULE); + &rv3029_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); @@ -412,16 +800,17 @@ static int rv3029c2_probe(struct i2c_client *client, return 0; } -static struct i2c_driver rv3029c2_driver = { +static struct i2c_driver rv3029_driver = { .driver = { .name = "rtc-rv3029c2", }, - .probe = rv3029c2_probe, - .id_table = rv3029c2_id, + .probe = rv3029_probe, + .id_table = rv3029_id, }; -module_i2c_driver(rv3029c2_driver); +module_i2c_driver(rv3029_driver); MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>"); -MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver"); +MODULE_AUTHOR("Michael Buesch <m@bues.ch>"); +MODULE_DESCRIPTION("Micro Crystal RV3029 RTC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 7155c0816..f623038e5 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -52,7 +52,7 @@ struct rv8803_data { struct i2c_client *client; struct rtc_device *rtc; - spinlock_t flags_lock; + struct mutex flags_lock; u8 ctrl; }; @@ -61,13 +61,16 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) struct i2c_client *client = dev_id; struct rv8803_data *rv8803 = i2c_get_clientdata(client); unsigned long events = 0; - int flags; + int flags, try = 0; - spin_lock(&rv8803->flags_lock); + mutex_lock(&rv8803->flags_lock); - flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + do { + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + try++; + } while ((flags == -ENXIO) && (try < 3)); if (flags <= 0) { - spin_unlock(&rv8803->flags_lock); + mutex_unlock(&rv8803->flags_lock); return IRQ_NONE; } @@ -102,7 +105,7 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) rv8803->ctrl); } - spin_unlock(&rv8803->flags_lock); + mutex_unlock(&rv8803->flags_lock); return IRQ_HANDLED; } @@ -155,7 +158,6 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) struct rv8803_data *rv8803 = dev_get_drvdata(dev); u8 date[7]; int flags, ret; - unsigned long irqflags; if ((tm->tm_year < 100) || (tm->tm_year > 199)) return -EINVAL; @@ -173,18 +175,18 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) if (ret < 0) return ret; - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG); if (flags < 0) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return flags; } ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, flags & ~RV8803_FLAG_V2F); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return ret; } @@ -226,7 +228,6 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) u8 alarmvals[3]; u8 ctrl[2]; int ret, err; - unsigned long irqflags; /* The alarm has no seconds, round up to nearest minute */ if (alrm->time.tm_sec) { @@ -236,11 +237,11 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) rtc_time64_to_tm(alarm_time, &alrm->time); } - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl); if (ret != 2) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return ret < 0 ? ret : -EIO; } @@ -253,14 +254,14 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL, rv8803->ctrl); if (err) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return err; } } ctrl[1] &= ~RV8803_FLAG_AF; err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); if (err) return err; @@ -289,7 +290,6 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled) struct i2c_client *client = to_i2c_client(dev); struct rv8803_data *rv8803 = dev_get_drvdata(dev); int ctrl, flags, err; - unsigned long irqflags; ctrl = rv8803->ctrl; @@ -305,15 +305,15 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled) ctrl &= ~RV8803_CTRL_AIE; } - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); if (flags < 0) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return flags; } flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF); err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); if (err) return err; @@ -333,7 +333,6 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) struct i2c_client *client = to_i2c_client(dev); struct rv8803_data *rv8803 = dev_get_drvdata(dev); int flags, ret = 0; - unsigned long irqflags; switch (cmd) { case RTC_VL_READ: @@ -355,16 +354,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) return 0; case RTC_VL_CLR: - spin_lock_irqsave(&rv8803->flags_lock, irqflags); + mutex_lock(&rv8803->flags_lock); flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); if (flags < 0) { - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); return flags; } flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F); ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); - spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + mutex_unlock(&rv8803->flags_lock); if (ret < 0) return ret; @@ -428,7 +427,7 @@ static int rv8803_probe(struct i2c_client *client, { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rv8803_data *rv8803; - int err, flags; + int err, flags, try = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { @@ -441,10 +440,20 @@ static int rv8803_probe(struct i2c_client *client, if (!rv8803) return -ENOMEM; + mutex_init(&rv8803->flags_lock); rv8803->client = client; i2c_set_clientdata(client, rv8803); - flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + /* + * There is a 60µs window where the RTC may not reply on the i2c bus in + * that case, the transfer is not ACKed. In that case, ensure there are + * multiple attempts. + */ + do { + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + try++; + } while ((flags == -ENXIO) && (try < 3)); + if (flags < 0) return flags; @@ -479,8 +488,12 @@ static int rv8803_probe(struct i2c_client *client, return PTR_ERR(rv8803->rtc); } - err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT, - RV8803_EXT_WADA); + try = 0; + do { + err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT, + RV8803_EXT_WADA); + try++; + } while ((err == -ENXIO) && (try < 3)); if (err) return err; diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c new file mode 100644 index 000000000..bbad00b23 --- /dev/null +++ b/drivers/rtc/rtc-rx6110.c @@ -0,0 +1,402 @@ +/* + * Driver for the Epson RTC module RX-6110 SA + * + * Copyright(C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * Copyright(C) SEIKO EPSON CORPORATION 2013. All rights reserved. + * + * This driver software is distributed as is, without any warranty of any kind, + * either express or implied as further specified in the GNU Public License. + * This software may be used and distributed according to the terms of the GNU + * Public License, version 2 as published by the Free Software Foundation. + * See the file COPYING in the main directory of this archive for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/bcd.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/spi/spi.h> + +/* RX-6110 Register definitions */ +#define RX6110_REG_SEC 0x10 +#define RX6110_REG_MIN 0x11 +#define RX6110_REG_HOUR 0x12 +#define RX6110_REG_WDAY 0x13 +#define RX6110_REG_MDAY 0x14 +#define RX6110_REG_MONTH 0x15 +#define RX6110_REG_YEAR 0x16 +#define RX6110_REG_RES1 0x17 +#define RX6110_REG_ALMIN 0x18 +#define RX6110_REG_ALHOUR 0x19 +#define RX6110_REG_ALWDAY 0x1A +#define RX6110_REG_TCOUNT0 0x1B +#define RX6110_REG_TCOUNT1 0x1C +#define RX6110_REG_EXT 0x1D +#define RX6110_REG_FLAG 0x1E +#define RX6110_REG_CTRL 0x1F +#define RX6110_REG_USER0 0x20 +#define RX6110_REG_USER1 0x21 +#define RX6110_REG_USER2 0x22 +#define RX6110_REG_USER3 0x23 +#define RX6110_REG_USER4 0x24 +#define RX6110_REG_USER5 0x25 +#define RX6110_REG_USER6 0x26 +#define RX6110_REG_USER7 0x27 +#define RX6110_REG_USER8 0x28 +#define RX6110_REG_USER9 0x29 +#define RX6110_REG_USERA 0x2A +#define RX6110_REG_USERB 0x2B +#define RX6110_REG_USERC 0x2C +#define RX6110_REG_USERD 0x2D +#define RX6110_REG_USERE 0x2E +#define RX6110_REG_USERF 0x2F +#define RX6110_REG_RES2 0x30 +#define RX6110_REG_RES3 0x31 +#define RX6110_REG_IRQ 0x32 + +#define RX6110_BIT_ALARM_EN BIT(7) + +/* Extension Register (1Dh) bit positions */ +#define RX6110_BIT_EXT_TSEL0 BIT(0) +#define RX6110_BIT_EXT_TSEL1 BIT(1) +#define RX6110_BIT_EXT_TSEL2 BIT(2) +#define RX6110_BIT_EXT_WADA BIT(3) +#define RX6110_BIT_EXT_TE BIT(4) +#define RX6110_BIT_EXT_USEL BIT(5) +#define RX6110_BIT_EXT_FSEL0 BIT(6) +#define RX6110_BIT_EXT_FSEL1 BIT(7) + +/* Flag Register (1Eh) bit positions */ +#define RX6110_BIT_FLAG_VLF BIT(1) +#define RX6110_BIT_FLAG_AF BIT(3) +#define RX6110_BIT_FLAG_TF BIT(4) +#define RX6110_BIT_FLAG_UF BIT(5) + +/* Control Register (1Fh) bit positions */ +#define RX6110_BIT_CTRL_TBKE BIT(0) +#define RX6110_BIT_CTRL_TBKON BIT(1) +#define RX6110_BIT_CTRL_TSTP BIT(2) +#define RX6110_BIT_CTRL_AIE BIT(3) +#define RX6110_BIT_CTRL_TIE BIT(4) +#define RX6110_BIT_CTRL_UIE BIT(5) +#define RX6110_BIT_CTRL_STOP BIT(6) +#define RX6110_BIT_CTRL_TEST BIT(7) + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WDAY, + RTC_MDAY, + RTC_MONTH, + RTC_YEAR, + RTC_NR_TIME +}; + +#define RX6110_DRIVER_NAME "rx6110" + +struct rx6110_data { + struct rtc_device *rtc; + struct regmap *regmap; +}; + +/** + * rx6110_rtc_tm_to_data - convert rtc_time to native time encoding + * + * @tm: holds date and time + * @data: holds the encoding in rx6110 native form + */ +static int rx6110_rtc_tm_to_data(struct rtc_time *tm, u8 *data) +{ + pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year); + + /* + * The year in the RTC is a value between 0 and 99. + * Assume that this represents the current century + * and disregard all other values. + */ + if (tm->tm_year < 100 || tm->tm_year >= 200) + return -EINVAL; + + data[RTC_SEC] = bin2bcd(tm->tm_sec); + data[RTC_MIN] = bin2bcd(tm->tm_min); + data[RTC_HOUR] = bin2bcd(tm->tm_hour); + data[RTC_WDAY] = BIT(bin2bcd(tm->tm_wday)); + data[RTC_MDAY] = bin2bcd(tm->tm_mday); + data[RTC_MONTH] = bin2bcd(tm->tm_mon + 1); + data[RTC_YEAR] = bin2bcd(tm->tm_year % 100); + + return 0; +} + +/** + * rx6110_data_to_rtc_tm - convert native time encoding to rtc_time + * + * @data: holds the encoding in rx6110 native form + * @tm: holds date and time + */ +static int rx6110_data_to_rtc_tm(u8 *data, struct rtc_time *tm) +{ + tm->tm_sec = bcd2bin(data[RTC_SEC] & 0x7f); + tm->tm_min = bcd2bin(data[RTC_MIN] & 0x7f); + /* only 24-hour clock */ + tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); + tm->tm_wday = ffs(data[RTC_WDAY] & 0x7f); + tm->tm_mday = bcd2bin(data[RTC_MDAY] & 0x3f); + tm->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1f) - 1; + tm->tm_year = bcd2bin(data[RTC_YEAR]) + 100; + + pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year); + + /* + * The year in the RTC is a value between 0 and 99. + * Assume that this represents the current century + * and disregard all other values. + */ + if (tm->tm_year < 100 || tm->tm_year >= 200) + return -EINVAL; + + return 0; +} + +/** + * rx6110_set_time - set the current time in the rx6110 registers + * + * @dev: the rtc device in use + * @tm: holds date and time + * + * BUG: The HW assumes every year that is a multiple of 4 to be a leap + * year. Next time this is wrong is 2100, which will not be a leap year + * + * Note: If STOP is not set/cleared, the clock will start when the seconds + * register is written + * + */ +static int rx6110_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rx6110_data *rx6110 = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int ret; + + ret = rx6110_rtc_tm_to_data(tm, data); + if (ret < 0) + return ret; + + /* set STOP bit before changing clock/calendar */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL, + RX6110_BIT_CTRL_STOP, RX6110_BIT_CTRL_STOP); + if (ret) + return ret; + + ret = regmap_bulk_write(rx6110->regmap, RX6110_REG_SEC, data, + RTC_NR_TIME); + if (ret) + return ret; + + /* The time in the RTC is valid. Be sure to have VLF cleared. */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG, + RX6110_BIT_FLAG_VLF, 0); + if (ret) + return ret; + + /* clear STOP bit after changing clock/calendar */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL, + RX6110_BIT_CTRL_STOP, 0); + + return ret; +} + +/** + * rx6110_get_time - get the current time from the rx6110 registers + * @dev: the rtc device in use + * @tm: holds date and time + */ +static int rx6110_get_time(struct device *dev, struct rtc_time *tm) +{ + struct rx6110_data *rx6110 = dev_get_drvdata(dev); + u8 data[RTC_NR_TIME]; + int flags; + int ret; + + ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags); + if (ret) + return -EINVAL; + + /* check for VLF Flag (set at power-on) */ + if ((flags & RX6110_BIT_FLAG_VLF)) { + dev_warn(dev, "Voltage low, data is invalid.\n"); + return -EINVAL; + } + + /* read registers to date */ + ret = regmap_bulk_read(rx6110->regmap, RX6110_REG_SEC, data, + RTC_NR_TIME); + if (ret) + return ret; + + ret = rx6110_data_to_rtc_tm(data, tm); + if (ret) + return ret; + + dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon, tm->tm_year); + + return rtc_valid_tm(tm); +} + +static const struct reg_sequence rx6110_default_regs[] = { + { RX6110_REG_RES1, 0xB8 }, + { RX6110_REG_RES2, 0x00 }, + { RX6110_REG_RES3, 0x10 }, + { RX6110_REG_IRQ, 0x00 }, + { RX6110_REG_ALMIN, 0x00 }, + { RX6110_REG_ALHOUR, 0x00 }, + { RX6110_REG_ALWDAY, 0x00 }, +}; + +/** + * rx6110_init - initialize the rx6110 registers + * + * @rx6110: pointer to the rx6110 struct in use + * + */ +static int rx6110_init(struct rx6110_data *rx6110) +{ + struct rtc_device *rtc = rx6110->rtc; + int flags; + int ret; + + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_EXT, + RX6110_BIT_EXT_TE, 0); + if (ret) + return ret; + + ret = regmap_register_patch(rx6110->regmap, rx6110_default_regs, + ARRAY_SIZE(rx6110_default_regs)); + if (ret) + return ret; + + ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags); + if (ret) + return ret; + + /* check for VLF Flag (set at power-on) */ + if ((flags & RX6110_BIT_FLAG_VLF)) + dev_warn(&rtc->dev, "Voltage low, data loss detected.\n"); + + /* check for Alarm Flag */ + if (flags & RX6110_BIT_FLAG_AF) + dev_warn(&rtc->dev, "An alarm may have been missed.\n"); + + /* check for Periodic Timer Flag */ + if (flags & RX6110_BIT_FLAG_TF) + dev_warn(&rtc->dev, "Periodic timer was detected\n"); + + /* check for Update Timer Flag */ + if (flags & RX6110_BIT_FLAG_UF) + dev_warn(&rtc->dev, "Update timer was detected\n"); + + /* clear all flags BUT VLF */ + ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG, + RX6110_BIT_FLAG_AF | + RX6110_BIT_FLAG_UF | + RX6110_BIT_FLAG_TF, + 0); + + return ret; +} + +static struct rtc_class_ops rx6110_rtc_ops = { + .read_time = rx6110_get_time, + .set_time = rx6110_set_time, +}; + +static struct regmap_config regmap_spi_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RX6110_REG_IRQ, + .read_flag_mask = 0x80, +}; + +/** + * rx6110_probe - initialize rtc driver + * @spi: pointer to spi device + */ +static int rx6110_probe(struct spi_device *spi) +{ + struct rx6110_data *rx6110; + int err; + + if ((spi->bits_per_word && spi->bits_per_word != 8) || + (spi->max_speed_hz > 2000000) || + (spi->mode != (SPI_CS_HIGH | SPI_CPOL | SPI_CPHA))) { + dev_warn(&spi->dev, "SPI settings: bits_per_word: %d, max_speed_hz: %d, mode: %xh\n", + spi->bits_per_word, spi->max_speed_hz, spi->mode); + dev_warn(&spi->dev, "driving device in an unsupported mode"); + } + + rx6110 = devm_kzalloc(&spi->dev, sizeof(*rx6110), GFP_KERNEL); + if (!rx6110) + return -ENOMEM; + + rx6110->regmap = devm_regmap_init_spi(spi, ®map_spi_config); + if (IS_ERR(rx6110->regmap)) { + dev_err(&spi->dev, "regmap init failed for rtc rx6110\n"); + return PTR_ERR(rx6110->regmap); + } + + spi_set_drvdata(spi, rx6110); + + rx6110->rtc = devm_rtc_device_register(&spi->dev, + RX6110_DRIVER_NAME, + &rx6110_rtc_ops, THIS_MODULE); + + if (IS_ERR(rx6110->rtc)) + return PTR_ERR(rx6110->rtc); + + err = rx6110_init(rx6110); + if (err) + return err; + + rx6110->rtc->max_user_freq = 1; + + return 0; +} + +static int rx6110_remove(struct spi_device *spi) +{ + return 0; +} + +static const struct spi_device_id rx6110_id[] = { + { "rx6110", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, rx6110_id); + +static struct spi_driver rx6110_driver = { + .driver = { + .name = RX6110_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = rx6110_probe, + .remove = rx6110_remove, + .id_table = rx6110_id, +}; + +module_spi_driver(rx6110_driver); + +MODULE_AUTHOR("Val Krutov <val.krutov@erd.epson.com>"); +MODULE_DESCRIPTION("RX-6110 SA RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 17341fead..9f105efbc 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -7,7 +7,7 @@ * All rights reserved. * * Modified by fengjh at rising.com.cn - * <http://lists.lm-sensors.org/mailman/listinfo/lm-sensors> + * <lm-sensors@lm-sensors.org> * 2006.11 * * Code cleanup by Sergei Poselenov, <sposelenov@emcraft.com> @@ -146,8 +146,10 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8025_data *rx8025 = i2c_get_clientdata(client); + struct mutex *lock = &rx8025->rtc->ops_lock; int status; + mutex_lock(lock); status = rx8025_read_reg(client, RX8025_REG_CTRL2); if (status < 0) goto out; @@ -172,6 +174,8 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) } out: + mutex_unlock(lock); + return IRQ_HANDLED; } @@ -340,7 +344,17 @@ static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t) if (client->irq <= 0) return -EINVAL; - /* Hardware alarm precision is 1 minute! */ + /* + * Hardware alarm precision is 1 minute! + * round up to nearest minute + */ + if (t->time.tm_sec) { + time64_t alarm_time = rtc_tm_to_time64(&t->time); + + alarm_time += 60 - t->time.tm_sec; + rtc_time64_to_tm(alarm_time, &t->time); + } + ald[0] = bin2bcd(t->time.tm_min); if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) ald[1] = bin2bcd(t->time.tm_hour); @@ -538,8 +552,9 @@ static int rx8025_probe(struct i2c_client *client, if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); err = devm_request_threaded_irq(&client->dev, client->irq, NULL, - rx8025_handle_irq, 0, "rx8025", - client); + rx8025_handle_irq, + IRQF_ONESHOT, + "rx8025", client); if (err) { dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); client->irq = 0; @@ -548,6 +563,9 @@ static int rx8025_probe(struct i2c_client *client, rx8025->rtc->max_user_freq = 1; + /* the rx8025 alarm only supports a minute accuracy */ + rx8025->rtc->uie_unsupported = 1; + err = rx8025_sysfs_register(&client->dev); return err; } diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index ffb860d18..d01ad7e80 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -501,18 +501,27 @@ static int s3c_rtc_probe(struct platform_device *pdev) info->rtc_clk = devm_clk_get(&pdev->dev, "rtc"); if (IS_ERR(info->rtc_clk)) { - dev_err(&pdev->dev, "failed to find rtc clock\n"); - return PTR_ERR(info->rtc_clk); + ret = PTR_ERR(info->rtc_clk); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "failed to find rtc clock\n"); + else + dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n"); + return ret; } clk_prepare_enable(info->rtc_clk); if (info->data->needs_src_clk) { info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src"); if (IS_ERR(info->rtc_src_clk)) { - dev_err(&pdev->dev, - "failed to find rtc source clock\n"); + ret = PTR_ERR(info->rtc_src_clk); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "failed to find rtc source clock\n"); + else + dev_dbg(&pdev->dev, + "probe deferred due to missing rtc src clk\n"); clk_disable_unprepare(info->rtc_clk); - return PTR_ERR(info->rtc_src_clk); + return ret; } clk_prepare_enable(info->rtc_src_clk); } diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 7407d7394..0477678d9 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -216,7 +216,7 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) * Read RTC_UDR_CON register and wait till UDR field is cleared. * This indicates that time/alarm update ended. */ -static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) +static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) { int ret, retry = UDR_READ_RETRY_CNT; unsigned int data; @@ -231,7 +231,7 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) return ret; } -static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, +static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, struct rtc_wkalrm *alarm) { int ret; @@ -264,7 +264,7 @@ static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, return 0; } -static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) +static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) { int ret; unsigned int data; @@ -288,7 +288,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) return ret; } -static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) +static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) { int ret; unsigned int data; diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 463e28606..63b9fb131 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -218,6 +218,34 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(wakealarm); +static ssize_t +offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + long offset; + + retval = rtc_read_offset(to_rtc_device(dev), &offset); + if (retval == 0) + retval = sprintf(buf, "%ld\n", offset); + + return retval; +} + +static ssize_t +offset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + ssize_t retval; + long offset; + + retval = kstrtol(buf, 10, &offset); + if (retval == 0) + retval = rtc_set_offset(to_rtc_device(dev), offset); + + return (retval < 0) ? retval : n; +} +static DEVICE_ATTR_RW(offset); + static struct attribute *rtc_attrs[] = { &dev_attr_name.attr, &dev_attr_date.attr, @@ -226,6 +254,7 @@ static struct attribute *rtc_attrs[] = { &dev_attr_max_user_freq.attr, &dev_attr_hctosys.attr, &dev_attr_wakealarm.attr, + &dev_attr_offset.attr, NULL, }; @@ -249,9 +278,13 @@ static umode_t rtc_attr_is_visible(struct kobject *kobj, struct rtc_device *rtc = to_rtc_device(dev); umode_t mode = attr->mode; - if (attr == &dev_attr_wakealarm.attr) + if (attr == &dev_attr_wakealarm.attr) { if (!rtc_does_wakealarm(rtc)) mode = 0; + } else if (attr == &dev_attr_offset.attr) { + if (!rtc->ops->set_offset) + mode = 0; + } return mode; } diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 3b6ce80a7..e404faac6 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -286,7 +286,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, tps6586x_rtc_irq, - IRQF_ONESHOT | IRQF_EARLY_RESUME, + IRQF_ONESHOT, dev_name(&pdev->dev), rtc); if (ret < 0) { dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n", diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index f42aa2b2d..5a3d53caa 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -268,7 +268,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev) } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME, + tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 27e254cde..737f26eb2 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -287,7 +287,7 @@ static int tps80031_rtc_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, tps80031_rtc_irq, - IRQF_ONESHOT | IRQF_EARLY_RESUME, + IRQF_ONESHOT, dev_name(&pdev->dev), rtc); if (ret < 0) { dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n", |