diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 81 | ||||
| -rw-r--r-- | drivers/rtc/Makefile | 5 | ||||
| -rw-r--r-- | drivers/rtc/rtc-at32ap700x.c | 317 | ||||
| -rw-r--r-- | drivers/rtc/rtc-cmos.c | 33 | ||||
| -rw-r--r-- | drivers/rtc/rtc-dev.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1216.c | 226 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1307.c | 300 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1553.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1742.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-m41t80.c | 917 | ||||
| -rw-r--r-- | drivers/rtc/rtc-m48t59.c | 491 | ||||
| -rw-r--r-- | drivers/rtc/rtc-max6900.c | 96 | ||||
| -rw-r--r-- | drivers/rtc/rtc-rs5c372.c | 95 | ||||
| -rw-r--r-- | drivers/rtc/rtc-stk17ta8.c | 420 |
14 files changed, 2776 insertions, 211 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4e4c10a7fd3a..9d8d40d5c8f7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -10,7 +10,6 @@ config RTC_LIB | |||
| 10 | 10 | ||
| 11 | config RTC_CLASS | 11 | config RTC_CLASS |
| 12 | tristate "RTC class" | 12 | tristate "RTC class" |
| 13 | depends on EXPERIMENTAL | ||
| 14 | default n | 13 | default n |
| 15 | select RTC_LIB | 14 | select RTC_LIB |
| 16 | help | 15 | help |
| @@ -39,6 +38,9 @@ config RTC_HCTOSYS_DEVICE | |||
| 39 | clock, usually rtc0. Initialization is done when the system | 38 | clock, usually rtc0. Initialization is done when the system |
| 40 | starts up, and when it resumes from a low power state. | 39 | starts up, and when it resumes from a low power state. |
| 41 | 40 | ||
| 41 | The driver for this RTC device must be loaded before late_initcall | ||
| 42 | functions run, so it must usually be statically linked. | ||
| 43 | |||
| 42 | This clock should be battery-backed, so that it reads the correct | 44 | This clock should be battery-backed, so that it reads the correct |
| 43 | time when the system boots from a power-off state. Otherwise, your | 45 | time when the system boots from a power-off state. Otherwise, your |
| 44 | system will need an external clock source (like an NTP server). | 46 | system will need an external clock source (like an NTP server). |
| @@ -119,7 +121,7 @@ config RTC_DRV_TEST | |||
| 119 | will be called rtc-test. | 121 | will be called rtc-test. |
| 120 | 122 | ||
| 121 | comment "I2C RTC drivers" | 123 | comment "I2C RTC drivers" |
| 122 | depends on RTC_CLASS | 124 | depends on RTC_CLASS && I2C |
| 123 | 125 | ||
| 124 | config RTC_DRV_DS1307 | 126 | config RTC_DRV_DS1307 |
| 125 | tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" | 127 | tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" |
| @@ -160,11 +162,11 @@ config RTC_DRV_MAX6900 | |||
| 160 | will be called rtc-max6900. | 162 | will be called rtc-max6900. |
| 161 | 163 | ||
| 162 | config RTC_DRV_RS5C372 | 164 | config RTC_DRV_RS5C372 |
| 163 | tristate "Ricoh RS5C372A/B" | 165 | tristate "Ricoh RS5C372A/B, RV5C386, RV5C387A" |
| 164 | depends on RTC_CLASS && I2C | 166 | depends on RTC_CLASS && I2C |
| 165 | help | 167 | help |
| 166 | If you say yes here you get support for the | 168 | If you say yes here you get support for the |
| 167 | Ricoh RS5C372A and RS5C372B RTC chips. | 169 | Ricoh RS5C372A, RS5C372B, RV5C386, and RV5C387A RTC chips. |
| 168 | 170 | ||
| 169 | This driver can also be built as a module. If so, the module | 171 | This driver can also be built as a module. If so, the module |
| 170 | will be called rtc-rs5c372. | 172 | will be called rtc-rs5c372. |
| @@ -213,12 +215,40 @@ config RTC_DRV_PCF8583 | |||
| 213 | This driver can also be built as a module. If so, the module | 215 | This driver can also be built as a module. If so, the module |
| 214 | will be called rtc-pcf8583. | 216 | will be called rtc-pcf8583. |
| 215 | 217 | ||
| 218 | config RTC_DRV_M41T80 | ||
| 219 | tristate "ST M41T80 series RTC" | ||
| 220 | depends on RTC_CLASS && I2C | ||
| 221 | help | ||
| 222 | If you say Y here you will get support for the | ||
| 223 | ST M41T80 RTC chips series. Currently following chips are | ||
| 224 | supported: M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85 | ||
| 225 | and M41ST87. | ||
| 226 | |||
| 227 | This driver can also be built as a module. If so, the module | ||
| 228 | will be called rtc-m41t80. | ||
| 229 | |||
| 230 | config RTC_DRV_M41T80_WDT | ||
| 231 | bool "ST M41T80 series RTC watchdog timer" | ||
| 232 | depends on RTC_DRV_M41T80 | ||
| 233 | help | ||
| 234 | If you say Y here you will get support for the | ||
| 235 | watchdog timer in ST M41T80 RTC chips series. | ||
| 236 | |||
| 237 | config RTC_DRV_TWL92330 | ||
| 238 | boolean "TI TWL92330/Menelaus" | ||
| 239 | depends on RTC_CLASS && I2C && MENELAUS | ||
| 240 | help | ||
| 241 | If you say yes here you get support for the RTC on the | ||
| 242 | TWL92330 "Menelaus" power mangement chip, used with OMAP2 | ||
| 243 | platforms. The support is integrated with the rest of | ||
| 244 | the Menelaus driver; it's not separate module. | ||
| 245 | |||
| 216 | comment "SPI RTC drivers" | 246 | comment "SPI RTC drivers" |
| 217 | depends on RTC_CLASS | 247 | depends on RTC_CLASS && SPI_MASTER |
| 218 | 248 | ||
| 219 | config RTC_DRV_RS5C348 | 249 | config RTC_DRV_RS5C348 |
| 220 | tristate "Ricoh RS5C348A/B" | 250 | tristate "Ricoh RS5C348A/B" |
| 221 | depends on RTC_CLASS && SPI | 251 | depends on RTC_CLASS && SPI_MASTER |
| 222 | help | 252 | help |
| 223 | If you say yes here you get support for the | 253 | If you say yes here you get support for the |
| 224 | Ricoh RS5C348A and RS5C348B RTC chips. | 254 | Ricoh RS5C348A and RS5C348B RTC chips. |
| @@ -228,7 +258,7 @@ config RTC_DRV_RS5C348 | |||
| 228 | 258 | ||
| 229 | config RTC_DRV_MAX6902 | 259 | config RTC_DRV_MAX6902 |
| 230 | tristate "Maxim 6902" | 260 | tristate "Maxim 6902" |
| 231 | depends on RTC_CLASS && SPI | 261 | depends on RTC_CLASS && SPI_MASTER |
| 232 | help | 262 | help |
| 233 | If you say yes here you will get support for the | 263 | If you say yes here you will get support for the |
| 234 | Maxim MAX6902 SPI RTC chip. | 264 | Maxim MAX6902 SPI RTC chip. |
| @@ -246,7 +276,7 @@ comment "Platform RTC drivers" | |||
| 246 | config RTC_DRV_CMOS | 276 | config RTC_DRV_CMOS |
| 247 | tristate "PC-style 'CMOS'" | 277 | tristate "PC-style 'CMOS'" |
| 248 | depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \ | 278 | depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \ |
| 249 | || M32R || ATARI || POWERPC || MIPS) | 279 | || M32R || ATARI || PPC || MIPS) |
| 250 | help | 280 | help |
| 251 | Say "yes" here to get direct support for the real time clock | 281 | Say "yes" here to get direct support for the real time clock |
| 252 | found in every PC or ACPI-based system, and some other boards. | 282 | found in every PC or ACPI-based system, and some other boards. |
| @@ -262,6 +292,12 @@ config RTC_DRV_CMOS | |||
| 262 | This driver can also be built as a module. If so, the module | 292 | This driver can also be built as a module. If so, the module |
| 263 | will be called rtc-cmos. | 293 | will be called rtc-cmos. |
| 264 | 294 | ||
| 295 | config RTC_DRV_DS1216 | ||
| 296 | tristate "Dallas DS1216" | ||
| 297 | depends on RTC_CLASS && SNI_RM | ||
| 298 | help | ||
| 299 | If you say yes here you get support for the Dallas DS1216 RTC chips. | ||
| 300 | |||
| 265 | config RTC_DRV_DS1553 | 301 | config RTC_DRV_DS1553 |
| 266 | tristate "Dallas DS1553" | 302 | tristate "Dallas DS1553" |
| 267 | depends on RTC_CLASS | 303 | depends on RTC_CLASS |
| @@ -272,6 +308,16 @@ config RTC_DRV_DS1553 | |||
| 272 | This driver can also be built as a module. If so, the module | 308 | This driver can also be built as a module. If so, the module |
| 273 | will be called rtc-ds1553. | 309 | will be called rtc-ds1553. |
| 274 | 310 | ||
| 311 | config RTC_DRV_STK17TA8 | ||
| 312 | tristate "Simtek STK17TA8" | ||
| 313 | depends on RTC_CLASS | ||
| 314 | help | ||
| 315 | If you say yes here you get support for the | ||
| 316 | Simtek STK17TA8 timekeeping chip. | ||
| 317 | |||
| 318 | This driver can also be built as a module. If so, the module | ||
| 319 | will be called rtc-stk17ta8. | ||
| 320 | |||
| 275 | config RTC_DRV_DS1742 | 321 | config RTC_DRV_DS1742 |
| 276 | tristate "Dallas DS1742/1743" | 322 | tristate "Dallas DS1742/1743" |
| 277 | depends on RTC_CLASS | 323 | depends on RTC_CLASS |
| @@ -292,6 +338,16 @@ config RTC_DRV_M48T86 | |||
| 292 | This driver can also be built as a module. If so, the module | 338 | This driver can also be built as a module. If so, the module |
| 293 | will be called rtc-m48t86. | 339 | will be called rtc-m48t86. |
| 294 | 340 | ||
| 341 | config RTC_DRV_M48T59 | ||
| 342 | tristate "ST M48T59" | ||
| 343 | depends on RTC_CLASS | ||
| 344 | help | ||
| 345 | If you say Y here you will get support for the | ||
| 346 | ST M48T59 RTC chip. | ||
| 347 | |||
| 348 | This driver can also be built as a module, if so, the module | ||
| 349 | will be called "rtc-m48t59". | ||
| 350 | |||
| 295 | config RTC_DRV_V3020 | 351 | config RTC_DRV_V3020 |
| 296 | tristate "EM Microelectronic V3020" | 352 | tristate "EM Microelectronic V3020" |
| 297 | depends on RTC_CLASS | 353 | depends on RTC_CLASS |
| @@ -351,7 +407,7 @@ config RTC_DRV_SA1100 | |||
| 351 | 407 | ||
| 352 | config RTC_DRV_SH | 408 | config RTC_DRV_SH |
| 353 | tristate "SuperH On-Chip RTC" | 409 | tristate "SuperH On-Chip RTC" |
| 354 | depends on RTC_CLASS && SUPERH | 410 | depends on RTC_CLASS && SUPERH && (CPU_SH3 || CPU_SH4) |
| 355 | help | 411 | help |
| 356 | Say Y here to enable support for the on-chip RTC found in | 412 | Say Y here to enable support for the on-chip RTC found in |
| 357 | most SuperH processors. | 413 | most SuperH processors. |
| @@ -379,6 +435,13 @@ config RTC_DRV_PL031 | |||
| 379 | To compile this driver as a module, choose M here: the | 435 | To compile this driver as a module, choose M here: the |
| 380 | module will be called rtc-pl031. | 436 | module will be called rtc-pl031. |
| 381 | 437 | ||
| 438 | config RTC_DRV_AT32AP700X | ||
| 439 | tristate "AT32AP700X series RTC" | ||
| 440 | depends on RTC_CLASS && PLATFORM_AT32AP | ||
| 441 | help | ||
| 442 | Driver for the internal RTC (Realtime Clock) on Atmel AVR32 | ||
| 443 | AT32AP700x family processors. | ||
| 444 | |||
| 382 | config RTC_DRV_AT91RM9200 | 445 | config RTC_DRV_AT91RM9200 |
| 383 | tristate "AT91RM9200" | 446 | tristate "AT91RM9200" |
| 384 | depends on RTC_CLASS && ARCH_AT91RM9200 | 447 | depends on RTC_CLASS && ARCH_AT91RM9200 |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index a1afbc236073..7ede9e725360 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
| @@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o | |||
| 19 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | 19 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o |
| 20 | obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o | 20 | obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o |
| 21 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | 21 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o |
| 22 | obj-$(CONFIG_RTC_DRV_AT32AP700X) += rtc-at32ap700x.o | ||
| 22 | obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o | 23 | obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o |
| 23 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | 24 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o |
| 24 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o | 25 | obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o |
| @@ -28,8 +29,10 @@ obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o | |||
| 28 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o | 29 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o |
| 29 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o | 30 | obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o |
| 30 | obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o | 31 | obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o |
| 32 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o | ||
| 31 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o | 33 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o |
| 32 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o | 34 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o |
| 35 | obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o | ||
| 33 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o | 36 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o |
| 34 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 37 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
| 35 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | 38 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o |
| @@ -41,3 +44,5 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o | |||
| 41 | obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o | 44 | obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o |
| 42 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o | 45 | obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o |
| 43 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o | 46 | obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o |
| 47 | obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o | ||
| 48 | obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o | ||
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c new file mode 100644 index 000000000000..2999214ca534 --- /dev/null +++ b/drivers/rtc/rtc-at32ap700x.c | |||
| @@ -0,0 +1,317 @@ | |||
| 1 | /* | ||
| 2 | * An RTC driver for the AVR32 AT32AP700x processor series. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007 Atmel Corporation | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published | ||
| 8 | * by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/rtc.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | |||
| 17 | /* | ||
| 18 | * This is a bare-bones RTC. It runs during most system sleep states, but has | ||
| 19 | * no battery backup and gets reset during system restart. It must be | ||
| 20 | * initialized from an external clock (network, I2C, etc) before it can be of | ||
| 21 | * much use. | ||
| 22 | * | ||
| 23 | * The alarm functionality is limited by the hardware, not supporting | ||
| 24 | * periodic interrupts. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #define RTC_CTRL 0x00 | ||
| 28 | #define RTC_CTRL_EN 0 | ||
| 29 | #define RTC_CTRL_PCLR 1 | ||
| 30 | #define RTC_CTRL_TOPEN 2 | ||
| 31 | #define RTC_CTRL_PSEL 8 | ||
| 32 | |||
| 33 | #define RTC_VAL 0x04 | ||
| 34 | |||
| 35 | #define RTC_TOP 0x08 | ||
| 36 | |||
| 37 | #define RTC_IER 0x10 | ||
| 38 | #define RTC_IER_TOPI 0 | ||
| 39 | |||
| 40 | #define RTC_IDR 0x14 | ||
| 41 | #define RTC_IDR_TOPI 0 | ||
| 42 | |||
| 43 | #define RTC_IMR 0x18 | ||
| 44 | #define RTC_IMR_TOPI 0 | ||
| 45 | |||
| 46 | #define RTC_ISR 0x1c | ||
| 47 | #define RTC_ISR_TOPI 0 | ||
| 48 | |||
| 49 | #define RTC_ICR 0x20 | ||
| 50 | #define RTC_ICR_TOPI 0 | ||
| 51 | |||
| 52 | #define RTC_BIT(name) (1 << RTC_##name) | ||
| 53 | #define RTC_BF(name, value) ((value) << RTC_##name) | ||
| 54 | |||
| 55 | #define rtc_readl(dev, reg) \ | ||
| 56 | __raw_readl((dev)->regs + RTC_##reg) | ||
| 57 | #define rtc_writel(dev, reg, value) \ | ||
| 58 | __raw_writel((value), (dev)->regs + RTC_##reg) | ||
| 59 | |||
| 60 | struct rtc_at32ap700x { | ||
| 61 | struct rtc_device *rtc; | ||
| 62 | void __iomem *regs; | ||
| 63 | unsigned long alarm_time; | ||
| 64 | unsigned long irq; | ||
| 65 | /* Protect against concurrent register access. */ | ||
| 66 | spinlock_t lock; | ||
| 67 | }; | ||
| 68 | |||
| 69 | static int at32_rtc_readtime(struct device *dev, struct rtc_time *tm) | ||
| 70 | { | ||
| 71 | struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); | ||
| 72 | unsigned long now; | ||
| 73 | |||
| 74 | now = rtc_readl(rtc, VAL); | ||
| 75 | rtc_time_to_tm(now, tm); | ||
| 76 | |||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int at32_rtc_settime(struct device *dev, struct rtc_time *tm) | ||
| 81 | { | ||
| 82 | struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); | ||
| 83 | unsigned long now; | ||
| 84 | int ret; | ||
| 85 | |||
| 86 | ret = rtc_tm_to_time(tm, &now); | ||
| 87 | if (ret == 0) | ||
| 88 | rtc_writel(rtc, VAL, now); | ||
| 89 | |||
| 90 | return ret; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 94 | { | ||
| 95 | struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); | ||
| 96 | |||
| 97 | rtc_time_to_tm(rtc->alarm_time, &alrm->time); | ||
| 98 | alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0; | ||
| 99 | |||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 104 | { | ||
| 105 | struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); | ||
| 106 | unsigned long rtc_unix_time; | ||
| 107 | unsigned long alarm_unix_time; | ||
| 108 | int ret; | ||
| 109 | |||
| 110 | rtc_unix_time = rtc_readl(rtc, VAL); | ||
| 111 | |||
| 112 | ret = rtc_tm_to_time(&alrm->time, &alarm_unix_time); | ||
| 113 | if (ret) | ||
| 114 | return ret; | ||
| 115 | |||
| 116 | if (alarm_unix_time < rtc_unix_time) | ||
| 117 | return -EINVAL; | ||
| 118 | |||
| 119 | spin_lock_irq(&rtc->lock); | ||
| 120 | rtc->alarm_time = alarm_unix_time; | ||
| 121 | rtc_writel(rtc, TOP, rtc->alarm_time); | ||
| 122 | if (alrm->pending) | ||
| 123 | rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | ||
| 124 | | RTC_BIT(CTRL_TOPEN)); | ||
| 125 | else | ||
| 126 | rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | ||
| 127 | & ~RTC_BIT(CTRL_TOPEN)); | ||
| 128 | spin_unlock_irq(&rtc->lock); | ||
| 129 | |||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int at32_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
| 134 | unsigned long arg) | ||
| 135 | { | ||
| 136 | struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); | ||
| 137 | int ret = 0; | ||
| 138 | |||
| 139 | spin_lock_irq(&rtc->lock); | ||
| 140 | |||
| 141 | switch (cmd) { | ||
| 142 | case RTC_AIE_ON: | ||
| 143 | if (rtc_readl(rtc, VAL) > rtc->alarm_time) { | ||
| 144 | ret = -EINVAL; | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | ||
| 148 | | RTC_BIT(CTRL_TOPEN)); | ||
| 149 | rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); | ||
| 150 | rtc_writel(rtc, IER, RTC_BIT(IER_TOPI)); | ||
| 151 | break; | ||
| 152 | case RTC_AIE_OFF: | ||
| 153 | rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | ||
| 154 | & ~RTC_BIT(CTRL_TOPEN)); | ||
| 155 | rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); | ||
| 156 | rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); | ||
| 157 | break; | ||
| 158 | default: | ||
| 159 | ret = -ENOIOCTLCMD; | ||
| 160 | break; | ||
| 161 | } | ||
| 162 | |||
| 163 | spin_unlock_irq(&rtc->lock); | ||
| 164 | |||
| 165 | return ret; | ||
| 166 | } | ||
| 167 | |||
| 168 | static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id) | ||
| 169 | { | ||
| 170 | struct rtc_at32ap700x *rtc = (struct rtc_at32ap700x *)dev_id; | ||
| 171 | unsigned long isr = rtc_readl(rtc, ISR); | ||
| 172 | unsigned long events = 0; | ||
| 173 | int ret = IRQ_NONE; | ||
| 174 | |||
| 175 | spin_lock(&rtc->lock); | ||
| 176 | |||
| 177 | if (isr & RTC_BIT(ISR_TOPI)) { | ||
| 178 | rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI)); | ||
| 179 | rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); | ||
| 180 | rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | ||
| 181 | & ~RTC_BIT(CTRL_TOPEN)); | ||
| 182 | rtc_writel(rtc, VAL, rtc->alarm_time); | ||
| 183 | events = RTC_AF | RTC_IRQF; | ||
| 184 | rtc_update_irq(rtc->rtc, 1, events); | ||
| 185 | ret = IRQ_HANDLED; | ||
| 186 | } | ||
| 187 | |||
| 188 | spin_unlock(&rtc->lock); | ||
| 189 | |||
| 190 | return ret; | ||
| 191 | } | ||
| 192 | |||
| 193 | static struct rtc_class_ops at32_rtc_ops = { | ||
| 194 | .ioctl = at32_rtc_ioctl, | ||
| 195 | .read_time = at32_rtc_readtime, | ||
| 196 | .set_time = at32_rtc_settime, | ||
| 197 | .read_alarm = at32_rtc_readalarm, | ||
| 198 | .set_alarm = at32_rtc_setalarm, | ||
| 199 | }; | ||
| 200 | |||
| 201 | static int __init at32_rtc_probe(struct platform_device *pdev) | ||
| 202 | { | ||
| 203 | struct resource *regs; | ||
| 204 | struct rtc_at32ap700x *rtc; | ||
| 205 | int irq = -1; | ||
| 206 | int ret; | ||
| 207 | |||
| 208 | rtc = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL); | ||
| 209 | if (!rtc) { | ||
| 210 | dev_dbg(&pdev->dev, "out of memory\n"); | ||
| 211 | return -ENOMEM; | ||
| 212 | } | ||
| 213 | |||
| 214 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 215 | if (!regs) { | ||
| 216 | dev_dbg(&pdev->dev, "no mmio resource defined\n"); | ||
| 217 | ret = -ENXIO; | ||
| 218 | goto out; | ||
| 219 | } | ||
| 220 | |||
| 221 | irq = platform_get_irq(pdev, 0); | ||
| 222 | if (irq < 0) { | ||
| 223 | dev_dbg(&pdev->dev, "could not get irq\n"); | ||
| 224 | ret = -ENXIO; | ||
| 225 | goto out; | ||
| 226 | } | ||
| 227 | |||
| 228 | ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc); | ||
| 229 | if (ret) { | ||
| 230 | dev_dbg(&pdev->dev, "could not request irq %d\n", irq); | ||
| 231 | goto out; | ||
| 232 | } | ||
| 233 | |||
| 234 | rtc->irq = irq; | ||
| 235 | rtc->regs = ioremap(regs->start, regs->end - regs->start + 1); | ||
| 236 | if (!rtc->regs) { | ||
| 237 | ret = -ENOMEM; | ||
| 238 | dev_dbg(&pdev->dev, "could not map I/O memory\n"); | ||
| 239 | goto out_free_irq; | ||
| 240 | } | ||
| 241 | spin_lock_init(&rtc->lock); | ||
| 242 | |||
| 243 | /* | ||
| 244 | * Maybe init RTC: count from zero at 1 Hz, disable wrap irq. | ||
| 245 | * | ||
| 246 | * Do not reset VAL register, as it can hold an old time | ||
| 247 | * from last JTAG reset. | ||
| 248 | */ | ||
| 249 | if (!(rtc_readl(rtc, CTRL) & RTC_BIT(CTRL_EN))) { | ||
| 250 | rtc_writel(rtc, CTRL, RTC_BIT(CTRL_PCLR)); | ||
| 251 | rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI)); | ||
| 252 | rtc_writel(rtc, CTRL, RTC_BF(CTRL_PSEL, 0xe) | ||
| 253 | | RTC_BIT(CTRL_EN)); | ||
| 254 | } | ||
| 255 | |||
| 256 | rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
| 257 | &at32_rtc_ops, THIS_MODULE); | ||
| 258 | if (IS_ERR(rtc->rtc)) { | ||
| 259 | dev_dbg(&pdev->dev, "could not register rtc device\n"); | ||
| 260 | ret = PTR_ERR(rtc->rtc); | ||
| 261 | goto out_iounmap; | ||
| 262 | } | ||
| 263 | |||
| 264 | platform_set_drvdata(pdev, rtc); | ||
| 265 | |||
| 266 | dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", | ||
| 267 | (unsigned long)rtc->regs, rtc->irq); | ||
| 268 | |||
| 269 | return 0; | ||
| 270 | |||
| 271 | out_iounmap: | ||
| 272 | iounmap(rtc->regs); | ||
| 273 | out_free_irq: | ||
| 274 | free_irq(irq, rtc); | ||
| 275 | out: | ||
| 276 | kfree(rtc); | ||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int __exit at32_rtc_remove(struct platform_device *pdev) | ||
| 281 | { | ||
| 282 | struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev); | ||
| 283 | |||
| 284 | free_irq(rtc->irq, rtc); | ||
| 285 | iounmap(rtc->regs); | ||
| 286 | rtc_device_unregister(rtc->rtc); | ||
| 287 | kfree(rtc); | ||
| 288 | platform_set_drvdata(pdev, NULL); | ||
| 289 | |||
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | MODULE_ALIAS("at32ap700x_rtc"); | ||
| 294 | |||
| 295 | static struct platform_driver at32_rtc_driver = { | ||
| 296 | .remove = __exit_p(at32_rtc_remove), | ||
| 297 | .driver = { | ||
| 298 | .name = "at32ap700x_rtc", | ||
| 299 | .owner = THIS_MODULE, | ||
| 300 | }, | ||
| 301 | }; | ||
| 302 | |||
| 303 | static int __init at32_rtc_init(void) | ||
| 304 | { | ||
| 305 | return platform_driver_probe(&at32_rtc_driver, at32_rtc_probe); | ||
| 306 | } | ||
| 307 | module_init(at32_rtc_init); | ||
| 308 | |||
| 309 | static void __exit at32_rtc_exit(void) | ||
| 310 | { | ||
| 311 | platform_driver_unregister(&at32_rtc_driver); | ||
| 312 | } | ||
| 313 | module_exit(at32_rtc_exit); | ||
| 314 | |||
| 315 | MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); | ||
| 316 | MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x"); | ||
| 317 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index e24ea82dc35b..5d760bb6c2cd 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
| @@ -235,7 +235,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
| 235 | return 0; | 235 | return 0; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | static int cmos_set_freq(struct device *dev, int freq) | 238 | static int cmos_irq_set_freq(struct device *dev, int freq) |
| 239 | { | 239 | { |
| 240 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 240 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
| 241 | int f; | 241 | int f; |
| @@ -259,6 +259,34 @@ static int cmos_set_freq(struct device *dev, int freq) | |||
| 259 | return 0; | 259 | return 0; |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | static int cmos_irq_set_state(struct device *dev, int enabled) | ||
| 263 | { | ||
| 264 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | ||
| 265 | unsigned char rtc_control, rtc_intr; | ||
| 266 | unsigned long flags; | ||
| 267 | |||
| 268 | if (!is_valid_irq(cmos->irq)) | ||
| 269 | return -ENXIO; | ||
| 270 | |||
| 271 | spin_lock_irqsave(&rtc_lock, flags); | ||
| 272 | rtc_control = CMOS_READ(RTC_CONTROL); | ||
| 273 | |||
| 274 | if (enabled) | ||
| 275 | rtc_control |= RTC_PIE; | ||
| 276 | else | ||
| 277 | rtc_control &= ~RTC_PIE; | ||
| 278 | |||
| 279 | CMOS_WRITE(rtc_control, RTC_CONTROL); | ||
| 280 | |||
| 281 | rtc_intr = CMOS_READ(RTC_INTR_FLAGS); | ||
| 282 | rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; | ||
| 283 | if (is_intr(rtc_intr)) | ||
| 284 | rtc_update_irq(cmos->rtc, 1, rtc_intr); | ||
| 285 | |||
| 286 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 262 | #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) | 290 | #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) |
| 263 | 291 | ||
| 264 | static int | 292 | static int |
| @@ -360,7 +388,8 @@ static const struct rtc_class_ops cmos_rtc_ops = { | |||
| 360 | .read_alarm = cmos_read_alarm, | 388 | .read_alarm = cmos_read_alarm, |
| 361 | .set_alarm = cmos_set_alarm, | 389 | .set_alarm = cmos_set_alarm, |
| 362 | .proc = cmos_procfs, | 390 | .proc = cmos_procfs, |
| 363 | .irq_set_freq = cmos_set_freq, | 391 | .irq_set_freq = cmos_irq_set_freq, |
| 392 | .irq_set_state = cmos_irq_set_state, | ||
| 364 | }; | 393 | }; |
| 365 | 394 | ||
| 366 | /*----------------------------------------------------------------*/ | 395 | /*----------------------------------------------------------------*/ |
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index f4e5f0040ff7..304535942de2 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
| @@ -341,6 +341,8 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, | |||
| 341 | case RTC_IRQP_READ: | 341 | case RTC_IRQP_READ: |
| 342 | if (ops->irq_set_freq) | 342 | if (ops->irq_set_freq) |
| 343 | err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); | 343 | err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); |
| 344 | else | ||
| 345 | err = -ENOTTY; | ||
| 344 | break; | 346 | break; |
| 345 | 347 | ||
| 346 | case RTC_IRQP_SET: | 348 | case RTC_IRQP_SET: |
diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c new file mode 100644 index 000000000000..83efb88f8f23 --- /dev/null +++ b/drivers/rtc/rtc-ds1216.c | |||
| @@ -0,0 +1,226 @@ | |||
| 1 | /* | ||
| 2 | * Dallas DS1216 RTC driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Thomas Bogendoerfer | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/rtc.h> | ||
| 10 | #include <linux/platform_device.h> | ||
| 11 | #include <linux/bcd.h> | ||
| 12 | |||
| 13 | #define DRV_VERSION "0.1" | ||
| 14 | |||
| 15 | struct ds1216_regs { | ||
| 16 | u8 tsec; | ||
| 17 | u8 sec; | ||
| 18 | u8 min; | ||
| 19 | u8 hour; | ||
| 20 | u8 wday; | ||
| 21 | u8 mday; | ||
| 22 | u8 month; | ||
| 23 | u8 year; | ||
| 24 | }; | ||
| 25 | |||
| 26 | #define DS1216_HOUR_1224 (1 << 7) | ||
| 27 | #define DS1216_HOUR_AMPM (1 << 5) | ||
| 28 | |||
| 29 | struct ds1216_priv { | ||
| 30 | struct rtc_device *rtc; | ||
| 31 | void __iomem *ioaddr; | ||
| 32 | size_t size; | ||
| 33 | unsigned long baseaddr; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static const u8 magic[] = { | ||
| 37 | 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c | ||
| 38 | }; | ||
| 39 | |||
| 40 | /* | ||
| 41 | * Read the 64 bit we'd like to have - It a series | ||
| 42 | * of 64 bits showing up in the LSB of the base register. | ||
| 43 | * | ||
| 44 | */ | ||
| 45 | static void ds1216_read(u8 __iomem *ioaddr, u8 *buf) | ||
| 46 | { | ||
| 47 | unsigned char c; | ||
| 48 | int i, j; | ||
| 49 | |||
| 50 | for (i = 0; i < 8; i++) { | ||
| 51 | c = 0; | ||
| 52 | for (j = 0; j < 8; j++) | ||
| 53 | c |= (readb(ioaddr) & 0x1) << j; | ||
| 54 | buf[i] = c; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | static void ds1216_write(u8 __iomem *ioaddr, const u8 *buf) | ||
| 59 | { | ||
| 60 | unsigned char c; | ||
| 61 | int i, j; | ||
| 62 | |||
| 63 | for (i = 0; i < 8; i++) { | ||
| 64 | c = buf[i]; | ||
| 65 | for (j = 0; j < 8; j++) { | ||
| 66 | writeb(c, ioaddr); | ||
| 67 | c = c >> 1; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | static void ds1216_switch_ds_to_clock(u8 __iomem *ioaddr) | ||
| 73 | { | ||
| 74 | /* Reset magic pointer */ | ||
| 75 | readb(ioaddr); | ||
| 76 | /* Write 64 bit magic to DS1216 */ | ||
| 77 | ds1216_write(ioaddr, magic); | ||
| 78 | } | ||
| 79 | |||
| 80 | static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 81 | { | ||
| 82 | struct platform_device *pdev = to_platform_device(dev); | ||
| 83 | struct ds1216_priv *priv = platform_get_drvdata(pdev); | ||
| 84 | struct ds1216_regs regs; | ||
| 85 | |||
| 86 | ds1216_switch_ds_to_clock(priv->ioaddr); | ||
| 87 | ds1216_read(priv->ioaddr, (u8 *)®s); | ||
| 88 | |||
| 89 | tm->tm_sec = BCD2BIN(regs.sec); | ||
| 90 | tm->tm_min = BCD2BIN(regs.min); | ||
| 91 | if (regs.hour & DS1216_HOUR_1224) { | ||
| 92 | /* AM/PM mode */ | ||
| 93 | tm->tm_hour = BCD2BIN(regs.hour & 0x1f); | ||
| 94 | if (regs.hour & DS1216_HOUR_AMPM) | ||
| 95 | tm->tm_hour += 12; | ||
| 96 | } else | ||
| 97 | tm->tm_hour = BCD2BIN(regs.hour & 0x3f); | ||
| 98 | tm->tm_wday = (regs.wday & 7) - 1; | ||
| 99 | tm->tm_mday = BCD2BIN(regs.mday & 0x3f); | ||
| 100 | tm->tm_mon = BCD2BIN(regs.month & 0x1f); | ||
| 101 | tm->tm_year = BCD2BIN(regs.year); | ||
| 102 | if (tm->tm_year < 70) | ||
| 103 | tm->tm_year += 100; | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static int ds1216_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 108 | { | ||
| 109 | struct platform_device *pdev = to_platform_device(dev); | ||
| 110 | struct ds1216_priv *priv = platform_get_drvdata(pdev); | ||
| 111 | struct ds1216_regs regs; | ||
| 112 | |||
| 113 | ds1216_switch_ds_to_clock(priv->ioaddr); | ||
| 114 | ds1216_read(priv->ioaddr, (u8 *)®s); | ||
| 115 | |||
| 116 | regs.tsec = 0; /* clear 0.1 and 0.01 seconds */ | ||
| 117 | regs.sec = BIN2BCD(tm->tm_sec); | ||
| 118 | regs.min = BIN2BCD(tm->tm_min); | ||
| 119 | regs.hour &= DS1216_HOUR_1224; | ||
| 120 | if (regs.hour && tm->tm_hour > 12) { | ||
| 121 | regs.hour |= DS1216_HOUR_AMPM; | ||
| 122 | tm->tm_hour -= 12; | ||
| 123 | } | ||
| 124 | regs.hour |= BIN2BCD(tm->tm_hour); | ||
| 125 | regs.wday &= ~7; | ||
| 126 | regs.wday |= tm->tm_wday; | ||
| 127 | regs.mday = BIN2BCD(tm->tm_mday); | ||
| 128 | regs.month = BIN2BCD(tm->tm_mon); | ||
| 129 | regs.year = BIN2BCD(tm->tm_year % 100); | ||
| 130 | |||
| 131 | ds1216_switch_ds_to_clock(priv->ioaddr); | ||
| 132 | ds1216_write(priv->ioaddr, (u8 *)®s); | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | static const struct rtc_class_ops ds1216_rtc_ops = { | ||
| 137 | .read_time = ds1216_rtc_read_time, | ||
| 138 | .set_time = ds1216_rtc_set_time, | ||
| 139 | }; | ||
| 140 | |||
| 141 | static int __devinit ds1216_rtc_probe(struct platform_device *pdev) | ||
| 142 | { | ||
| 143 | struct rtc_device *rtc; | ||
| 144 | struct resource *res; | ||
| 145 | struct ds1216_priv *priv; | ||
| 146 | int ret = 0; | ||
| 147 | u8 dummy[8]; | ||
| 148 | |||
| 149 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 150 | if (!res) | ||
| 151 | return -ENODEV; | ||
| 152 | priv = kzalloc(sizeof *priv, GFP_KERNEL); | ||
| 153 | if (!priv) | ||
| 154 | return -ENOMEM; | ||
| 155 | priv->size = res->end - res->start + 1; | ||
| 156 | if (!request_mem_region(res->start, priv->size, pdev->name)) { | ||
| 157 | ret = -EBUSY; | ||
| 158 | goto out; | ||
| 159 | } | ||
| 160 | priv->baseaddr = res->start; | ||
| 161 | priv->ioaddr = ioremap(priv->baseaddr, priv->size); | ||
| 162 | if (!priv->ioaddr) { | ||
| 163 | ret = -ENOMEM; | ||
| 164 | goto out; | ||
| 165 | } | ||
| 166 | rtc = rtc_device_register("ds1216", &pdev->dev, | ||
| 167 | &ds1216_rtc_ops, THIS_MODULE); | ||
| 168 | if (IS_ERR(rtc)) { | ||
| 169 | ret = PTR_ERR(rtc); | ||
| 170 | goto out; | ||
| 171 | } | ||
| 172 | priv->rtc = rtc; | ||
| 173 | platform_set_drvdata(pdev, priv); | ||
| 174 | |||
| 175 | /* dummy read to get clock into a known state */ | ||
| 176 | ds1216_read(priv->ioaddr, dummy); | ||
| 177 | return 0; | ||
| 178 | |||
| 179 | out: | ||
| 180 | if (priv->rtc) | ||
| 181 | rtc_device_unregister(priv->rtc); | ||
| 182 | if (priv->ioaddr) | ||
| 183 | iounmap(priv->ioaddr); | ||
| 184 | if (priv->baseaddr) | ||
| 185 | release_mem_region(priv->baseaddr, priv->size); | ||
| 186 | kfree(priv); | ||
| 187 | return ret; | ||
| 188 | } | ||
| 189 | |||
| 190 | static int __devexit ds1216_rtc_remove(struct platform_device *pdev) | ||
| 191 | { | ||
| 192 | struct ds1216_priv *priv = platform_get_drvdata(pdev); | ||
| 193 | |||
| 194 | rtc_device_unregister(priv->rtc); | ||
| 195 | iounmap(priv->ioaddr); | ||
| 196 | release_mem_region(priv->baseaddr, priv->size); | ||
| 197 | kfree(priv); | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | static struct platform_driver ds1216_rtc_platform_driver = { | ||
| 202 | .driver = { | ||
| 203 | .name = "rtc-ds1216", | ||
| 204 | .owner = THIS_MODULE, | ||
| 205 | }, | ||
| 206 | .probe = ds1216_rtc_probe, | ||
| 207 | .remove = __devexit_p(ds1216_rtc_remove), | ||
| 208 | }; | ||
| 209 | |||
| 210 | static int __init ds1216_rtc_init(void) | ||
| 211 | { | ||
| 212 | return platform_driver_register(&ds1216_rtc_platform_driver); | ||
| 213 | } | ||
| 214 | |||
| 215 | static void __exit ds1216_rtc_exit(void) | ||
| 216 | { | ||
| 217 | platform_driver_unregister(&ds1216_rtc_platform_driver); | ||
| 218 | } | ||
| 219 | |||
| 220 | MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>"); | ||
| 221 | MODULE_DESCRIPTION("DS1216 RTC driver"); | ||
| 222 | MODULE_LICENSE("GPL"); | ||
| 223 | MODULE_VERSION(DRV_VERSION); | ||
| 224 | |||
| 225 | module_init(ds1216_rtc_init); | ||
| 226 | module_exit(ds1216_rtc_exit); | ||
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 3f0f7b8fa813..5158a625671f 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
| @@ -24,29 +24,29 @@ | |||
| 24 | * setting the date and time), Linux can ignore the non-clock features. | 24 | * setting the date and time), Linux can ignore the non-clock features. |
| 25 | * That's a natural job for a factory or repair bench. | 25 | * That's a natural job for a factory or repair bench. |
| 26 | * | 26 | * |
| 27 | * If the I2C "force" mechanism is used, we assume the chip is a ds1337. | 27 | * This is currently a simple no-alarms driver. If your board has the |
| 28 | * (Much better would be board-specific tables of I2C devices, along with | 28 | * alarm irq wired up on a ds1337 or ds1339, and you want to use that, |
| 29 | * the platform_data drivers would use to sort such issues out.) | 29 | * then look at the rtc-rs5c372 driver for code to steal... |
| 30 | */ | 30 | */ |
| 31 | enum ds_type { | 31 | enum ds_type { |
| 32 | unknown = 0, | 32 | ds_1307, |
| 33 | ds_1307, /* or ds1338, ... */ | 33 | ds_1337, |
| 34 | ds_1337, /* or ds1339, ... */ | 34 | ds_1338, |
| 35 | ds_1340, /* or st m41t00, ... */ | 35 | ds_1339, |
| 36 | ds_1340, | ||
| 37 | m41t00, | ||
| 36 | // rs5c372 too? different address... | 38 | // rs5c372 too? different address... |
| 37 | }; | 39 | }; |
| 38 | 40 | ||
| 39 | static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END }; | ||
| 40 | |||
| 41 | I2C_CLIENT_INSMOD; | ||
| 42 | |||
| 43 | |||
| 44 | 41 | ||
| 45 | /* RTC registers don't differ much, except for the century flag */ | 42 | /* RTC registers don't differ much, except for the century flag */ |
| 46 | #define DS1307_REG_SECS 0x00 /* 00-59 */ | 43 | #define DS1307_REG_SECS 0x00 /* 00-59 */ |
| 47 | # define DS1307_BIT_CH 0x80 | 44 | # define DS1307_BIT_CH 0x80 |
| 45 | # define DS1340_BIT_nEOSC 0x80 | ||
| 48 | #define DS1307_REG_MIN 0x01 /* 00-59 */ | 46 | #define DS1307_REG_MIN 0x01 /* 00-59 */ |
| 49 | #define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */ | 47 | #define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */ |
| 48 | # define DS1307_BIT_12HR 0x40 /* in REG_HOUR */ | ||
| 49 | # define DS1307_BIT_PM 0x20 /* in REG_HOUR */ | ||
| 50 | # define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */ | 50 | # define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */ |
| 51 | # define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */ | 51 | # define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */ |
| 52 | #define DS1307_REG_WDAY 0x03 /* 01-07 */ | 52 | #define DS1307_REG_WDAY 0x03 /* 01-07 */ |
| @@ -56,11 +56,12 @@ I2C_CLIENT_INSMOD; | |||
| 56 | #define DS1307_REG_YEAR 0x06 /* 00-99 */ | 56 | #define DS1307_REG_YEAR 0x06 /* 00-99 */ |
| 57 | 57 | ||
| 58 | /* Other registers (control, status, alarms, trickle charge, NVRAM, etc) | 58 | /* Other registers (control, status, alarms, trickle charge, NVRAM, etc) |
| 59 | * start at 7, and they differ a lot. Only control and status matter for RTC; | 59 | * start at 7, and they differ a LOT. Only control and status matter for |
| 60 | * be careful using them. | 60 | * basic RTC date and time functionality; be careful using them. |
| 61 | */ | 61 | */ |
| 62 | #define DS1307_REG_CONTROL 0x07 | 62 | #define DS1307_REG_CONTROL 0x07 /* or ds1338 */ |
| 63 | # define DS1307_BIT_OUT 0x80 | 63 | # define DS1307_BIT_OUT 0x80 |
| 64 | # define DS1338_BIT_OSF 0x20 | ||
| 64 | # define DS1307_BIT_SQWE 0x10 | 65 | # define DS1307_BIT_SQWE 0x10 |
| 65 | # define DS1307_BIT_RS1 0x02 | 66 | # define DS1307_BIT_RS1 0x02 |
| 66 | # define DS1307_BIT_RS0 0x01 | 67 | # define DS1307_BIT_RS0 0x01 |
| @@ -71,6 +72,13 @@ I2C_CLIENT_INSMOD; | |||
| 71 | # define DS1337_BIT_INTCN 0x04 | 72 | # define DS1337_BIT_INTCN 0x04 |
| 72 | # define DS1337_BIT_A2IE 0x02 | 73 | # define DS1337_BIT_A2IE 0x02 |
| 73 | # define DS1337_BIT_A1IE 0x01 | 74 | # define DS1337_BIT_A1IE 0x01 |
| 75 | #define DS1340_REG_CONTROL 0x07 | ||
| 76 | # define DS1340_BIT_OUT 0x80 | ||
| 77 | # define DS1340_BIT_FT 0x40 | ||
| 78 | # define DS1340_BIT_CALIB_SIGN 0x20 | ||
| 79 | # define DS1340_M_CALIBRATION 0x1f | ||
| 80 | #define DS1340_REG_FLAG 0x09 | ||
| 81 | # define DS1340_BIT_OSF 0x80 | ||
| 74 | #define DS1337_REG_STATUS 0x0f | 82 | #define DS1337_REG_STATUS 0x0f |
| 75 | # define DS1337_BIT_OSF 0x80 | 83 | # define DS1337_BIT_OSF 0x80 |
| 76 | # define DS1337_BIT_A2I 0x02 | 84 | # define DS1337_BIT_A2I 0x02 |
| @@ -84,21 +92,63 @@ struct ds1307 { | |||
| 84 | u8 regs[8]; | 92 | u8 regs[8]; |
| 85 | enum ds_type type; | 93 | enum ds_type type; |
| 86 | struct i2c_msg msg[2]; | 94 | struct i2c_msg msg[2]; |
| 87 | struct i2c_client client; | 95 | struct i2c_client *client; |
| 96 | struct i2c_client dev; | ||
| 88 | struct rtc_device *rtc; | 97 | struct rtc_device *rtc; |
| 89 | }; | 98 | }; |
| 90 | 99 | ||
| 100 | struct chip_desc { | ||
| 101 | char name[9]; | ||
| 102 | unsigned nvram56:1; | ||
| 103 | unsigned alarm:1; | ||
| 104 | enum ds_type type; | ||
| 105 | }; | ||
| 106 | |||
| 107 | static const struct chip_desc chips[] = { { | ||
| 108 | .name = "ds1307", | ||
| 109 | .type = ds_1307, | ||
| 110 | .nvram56 = 1, | ||
| 111 | }, { | ||
| 112 | .name = "ds1337", | ||
| 113 | .type = ds_1337, | ||
| 114 | .alarm = 1, | ||
| 115 | }, { | ||
| 116 | .name = "ds1338", | ||
| 117 | .type = ds_1338, | ||
| 118 | .nvram56 = 1, | ||
| 119 | }, { | ||
| 120 | .name = "ds1339", | ||
| 121 | .type = ds_1339, | ||
| 122 | .alarm = 1, | ||
| 123 | }, { | ||
| 124 | .name = "ds1340", | ||
| 125 | .type = ds_1340, | ||
| 126 | }, { | ||
| 127 | .name = "m41t00", | ||
| 128 | .type = m41t00, | ||
| 129 | }, }; | ||
| 130 | |||
| 131 | static inline const struct chip_desc *find_chip(const char *s) | ||
| 132 | { | ||
| 133 | unsigned i; | ||
| 134 | |||
| 135 | for (i = 0; i < ARRAY_SIZE(chips); i++) | ||
| 136 | if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0) | ||
| 137 | return &chips[i]; | ||
| 138 | return NULL; | ||
| 139 | } | ||
| 91 | 140 | ||
| 92 | static int ds1307_get_time(struct device *dev, struct rtc_time *t) | 141 | static int ds1307_get_time(struct device *dev, struct rtc_time *t) |
| 93 | { | 142 | { |
| 94 | struct ds1307 *ds1307 = dev_get_drvdata(dev); | 143 | struct ds1307 *ds1307 = dev_get_drvdata(dev); |
| 95 | int tmp; | 144 | int tmp; |
| 96 | 145 | ||
| 97 | /* read the RTC registers all at once */ | 146 | /* read the RTC date and time registers all at once */ |
| 98 | ds1307->msg[1].flags = I2C_M_RD; | 147 | ds1307->msg[1].flags = I2C_M_RD; |
| 99 | ds1307->msg[1].len = 7; | 148 | ds1307->msg[1].len = 7; |
| 100 | 149 | ||
| 101 | tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2); | 150 | tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), |
| 151 | ds1307->msg, 2); | ||
| 102 | if (tmp != 2) { | 152 | if (tmp != 2) { |
| 103 | dev_err(dev, "%s error %d\n", "read", tmp); | 153 | dev_err(dev, "%s error %d\n", "read", tmp); |
| 104 | return -EIO; | 154 | return -EIO; |
| @@ -129,7 +179,8 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) | |||
| 129 | t->tm_hour, t->tm_mday, | 179 | t->tm_hour, t->tm_mday, |
| 130 | t->tm_mon, t->tm_year, t->tm_wday); | 180 | t->tm_mon, t->tm_year, t->tm_wday); |
| 131 | 181 | ||
| 132 | return 0; | 182 | /* initial clock setting can be undefined */ |
| 183 | return rtc_valid_tm(t); | ||
| 133 | } | 184 | } |
| 134 | 185 | ||
| 135 | static int ds1307_set_time(struct device *dev, struct rtc_time *t) | 186 | static int ds1307_set_time(struct device *dev, struct rtc_time *t) |
| @@ -157,11 +208,18 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) | |||
| 157 | tmp = t->tm_year - 100; | 208 | tmp = t->tm_year - 100; |
| 158 | buf[DS1307_REG_YEAR] = BIN2BCD(tmp); | 209 | buf[DS1307_REG_YEAR] = BIN2BCD(tmp); |
| 159 | 210 | ||
| 160 | if (ds1307->type == ds_1337) | 211 | switch (ds1307->type) { |
| 212 | case ds_1337: | ||
| 213 | case ds_1339: | ||
| 161 | buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; | 214 | buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; |
| 162 | else if (ds1307->type == ds_1340) | 215 | break; |
| 216 | case ds_1340: | ||
| 163 | buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN | 217 | buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN |
| 164 | | DS1340_BIT_CENTURY; | 218 | | DS1340_BIT_CENTURY; |
| 219 | break; | ||
| 220 | default: | ||
| 221 | break; | ||
| 222 | } | ||
| 165 | 223 | ||
| 166 | ds1307->msg[1].flags = 0; | 224 | ds1307->msg[1].flags = 0; |
| 167 | ds1307->msg[1].len = 8; | 225 | ds1307->msg[1].len = 8; |
| @@ -170,7 +228,8 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) | |||
| 170 | "write", buf[0], buf[1], buf[2], buf[3], | 228 | "write", buf[0], buf[1], buf[2], buf[3], |
| 171 | buf[4], buf[5], buf[6]); | 229 | buf[4], buf[5], buf[6]); |
| 172 | 230 | ||
| 173 | result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1); | 231 | result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), |
| 232 | &ds1307->msg[1], 1); | ||
| 174 | if (result != 1) { | 233 | if (result != 1) { |
| 175 | dev_err(dev, "%s error %d\n", "write", tmp); | 234 | dev_err(dev, "%s error %d\n", "write", tmp); |
| 176 | return -EIO; | 235 | return -EIO; |
| @@ -185,25 +244,29 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { | |||
| 185 | 244 | ||
| 186 | static struct i2c_driver ds1307_driver; | 245 | static struct i2c_driver ds1307_driver; |
| 187 | 246 | ||
| 188 | static int __devinit | 247 | static int __devinit ds1307_probe(struct i2c_client *client) |
| 189 | ds1307_detect(struct i2c_adapter *adapter, int address, int kind) | ||
| 190 | { | 248 | { |
| 191 | struct ds1307 *ds1307; | 249 | struct ds1307 *ds1307; |
| 192 | int err = -ENODEV; | 250 | int err = -ENODEV; |
| 193 | struct i2c_client *client; | ||
| 194 | int tmp; | 251 | int tmp; |
| 195 | 252 | const struct chip_desc *chip; | |
| 196 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) { | 253 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 197 | err = -ENOMEM; | 254 | |
| 198 | goto exit; | 255 | chip = find_chip(client->name); |
| 256 | if (!chip) { | ||
| 257 | dev_err(&client->dev, "unknown chip type '%s'\n", | ||
| 258 | client->name); | ||
| 259 | return -ENODEV; | ||
| 199 | } | 260 | } |
| 200 | 261 | ||
| 201 | client = &ds1307->client; | 262 | if (!i2c_check_functionality(adapter, |
| 202 | client->addr = address; | 263 | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) |
| 203 | client->adapter = adapter; | 264 | return -EIO; |
| 204 | client->driver = &ds1307_driver; | 265 | |
| 205 | client->flags = 0; | 266 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) |
| 267 | return -ENOMEM; | ||
| 206 | 268 | ||
| 269 | ds1307->client = client; | ||
| 207 | i2c_set_clientdata(client, ds1307); | 270 | i2c_set_clientdata(client, ds1307); |
| 208 | 271 | ||
| 209 | ds1307->msg[0].addr = client->addr; | 272 | ds1307->msg[0].addr = client->addr; |
| @@ -216,14 +279,16 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 216 | ds1307->msg[1].len = sizeof(ds1307->regs); | 279 | ds1307->msg[1].len = sizeof(ds1307->regs); |
| 217 | ds1307->msg[1].buf = ds1307->regs; | 280 | ds1307->msg[1].buf = ds1307->regs; |
| 218 | 281 | ||
| 219 | /* HACK: "force" implies "needs ds1337-style-oscillator setup" */ | 282 | ds1307->type = chip->type; |
| 220 | if (kind >= 0) { | ||
| 221 | ds1307->type = ds_1337; | ||
| 222 | 283 | ||
| 284 | switch (ds1307->type) { | ||
| 285 | case ds_1337: | ||
| 286 | case ds_1339: | ||
| 223 | ds1307->reg_addr = DS1337_REG_CONTROL; | 287 | ds1307->reg_addr = DS1337_REG_CONTROL; |
| 224 | ds1307->msg[1].len = 2; | 288 | ds1307->msg[1].len = 2; |
| 225 | 289 | ||
| 226 | tmp = i2c_transfer(client->adapter, ds1307->msg, 2); | 290 | /* get registers that the "rtc" read below won't read... */ |
| 291 | tmp = i2c_transfer(adapter, ds1307->msg, 2); | ||
| 227 | if (tmp != 2) { | 292 | if (tmp != 2) { |
| 228 | pr_debug("read error %d\n", tmp); | 293 | pr_debug("read error %d\n", tmp); |
| 229 | err = -EIO; | 294 | err = -EIO; |
| @@ -233,19 +298,26 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 233 | ds1307->reg_addr = 0; | 298 | ds1307->reg_addr = 0; |
| 234 | ds1307->msg[1].len = sizeof(ds1307->regs); | 299 | ds1307->msg[1].len = sizeof(ds1307->regs); |
| 235 | 300 | ||
| 236 | /* oscillator is off; need to turn it on */ | 301 | /* oscillator off? turn it on, so clock can tick. */ |
| 237 | if ((ds1307->regs[0] & DS1337_BIT_nEOSC) | 302 | if (ds1307->regs[0] & DS1337_BIT_nEOSC) |
| 238 | || (ds1307->regs[1] & DS1337_BIT_OSF)) { | 303 | i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, |
| 239 | printk(KERN_ERR "no ds1337 oscillator code\n"); | 304 | ds1307->regs[0] & ~DS1337_BIT_nEOSC); |
| 240 | goto exit_free; | 305 | |
| 306 | /* oscillator fault? clear flag, and warn */ | ||
| 307 | if (ds1307->regs[1] & DS1337_BIT_OSF) { | ||
| 308 | i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, | ||
| 309 | ds1307->regs[1] & ~DS1337_BIT_OSF); | ||
| 310 | dev_warn(&client->dev, "SET TIME!\n"); | ||
| 241 | } | 311 | } |
| 242 | } else | 312 | break; |
| 243 | ds1307->type = ds_1307; | 313 | default: |
| 314 | break; | ||
| 315 | } | ||
| 244 | 316 | ||
| 245 | read_rtc: | 317 | read_rtc: |
| 246 | /* read RTC registers */ | 318 | /* read RTC registers */ |
| 247 | 319 | ||
| 248 | tmp = i2c_transfer(client->adapter, ds1307->msg, 2); | 320 | tmp = i2c_transfer(adapter, ds1307->msg, 2); |
| 249 | if (tmp != 2) { | 321 | if (tmp != 2) { |
| 250 | pr_debug("read error %d\n", tmp); | 322 | pr_debug("read error %d\n", tmp); |
| 251 | err = -EIO; | 323 | err = -EIO; |
| @@ -257,72 +329,80 @@ read_rtc: | |||
| 257 | * still a few values that are clearly out-of-range. | 329 | * still a few values that are clearly out-of-range. |
| 258 | */ | 330 | */ |
| 259 | tmp = ds1307->regs[DS1307_REG_SECS]; | 331 | tmp = ds1307->regs[DS1307_REG_SECS]; |
| 260 | if (tmp & DS1307_BIT_CH) { | 332 | switch (ds1307->type) { |
| 261 | if (ds1307->type && ds1307->type != ds_1307) { | 333 | case ds_1340: |
| 262 | pr_debug("not a ds1307?\n"); | 334 | /* FIXME read register with DS1340_BIT_OSF, use that to |
| 263 | goto exit_free; | 335 | * trigger the "set time" warning (*after* restarting the |
| 264 | } | 336 | * oscillator!) instead of this weaker ds1307/m41t00 test. |
| 265 | ds1307->type = ds_1307; | ||
| 266 | |||
| 267 | /* this partial initialization should work for ds1307, | ||
| 268 | * ds1338, ds1340, st m41t00, and more. | ||
| 269 | */ | 337 | */ |
| 270 | dev_warn(&client->dev, "oscillator started; SET TIME!\n"); | 338 | case ds_1307: |
| 271 | i2c_smbus_write_byte_data(client, 0, 0); | 339 | case m41t00: |
| 272 | goto read_rtc; | 340 | /* clock halted? turn it on, so clock can tick. */ |
| 341 | if (tmp & DS1307_BIT_CH) { | ||
| 342 | i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); | ||
| 343 | dev_warn(&client->dev, "SET TIME!\n"); | ||
| 344 | goto read_rtc; | ||
| 345 | } | ||
| 346 | break; | ||
| 347 | case ds_1338: | ||
| 348 | /* clock halted? turn it on, so clock can tick. */ | ||
| 349 | if (tmp & DS1307_BIT_CH) | ||
| 350 | i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); | ||
| 351 | |||
| 352 | /* oscillator fault? clear flag, and warn */ | ||
| 353 | if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) { | ||
| 354 | i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL, | ||
| 355 | ds1307->regs[DS1337_REG_CONTROL] | ||
| 356 | & ~DS1338_BIT_OSF); | ||
| 357 | dev_warn(&client->dev, "SET TIME!\n"); | ||
| 358 | goto read_rtc; | ||
| 359 | } | ||
| 360 | break; | ||
| 361 | case ds_1337: | ||
| 362 | case ds_1339: | ||
| 363 | break; | ||
| 273 | } | 364 | } |
| 365 | |||
| 366 | tmp = ds1307->regs[DS1307_REG_SECS]; | ||
| 274 | tmp = BCD2BIN(tmp & 0x7f); | 367 | tmp = BCD2BIN(tmp & 0x7f); |
| 275 | if (tmp > 60) | 368 | if (tmp > 60) |
| 276 | goto exit_free; | 369 | goto exit_bad; |
| 277 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f); | 370 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f); |
| 278 | if (tmp > 60) | 371 | if (tmp > 60) |
| 279 | goto exit_free; | 372 | goto exit_bad; |
| 280 | 373 | ||
| 281 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f); | 374 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f); |
| 282 | if (tmp == 0 || tmp > 31) | 375 | if (tmp == 0 || tmp > 31) |
| 283 | goto exit_free; | 376 | goto exit_bad; |
| 284 | 377 | ||
| 285 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f); | 378 | tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f); |
| 286 | if (tmp == 0 || tmp > 12) | 379 | if (tmp == 0 || tmp > 12) |
| 287 | goto exit_free; | 380 | goto exit_bad; |
| 288 | 381 | ||
| 289 | /* force into in 24 hour mode (most chips) or | ||
| 290 | * disable century bit (ds1340) | ||
| 291 | */ | ||
| 292 | tmp = ds1307->regs[DS1307_REG_HOUR]; | 382 | tmp = ds1307->regs[DS1307_REG_HOUR]; |
| 293 | if (tmp & (1 << 6)) { | ||
| 294 | if (tmp & (1 << 5)) | ||
| 295 | tmp = BCD2BIN(tmp & 0x1f) + 12; | ||
| 296 | else | ||
| 297 | tmp = BCD2BIN(tmp); | ||
| 298 | i2c_smbus_write_byte_data(client, | ||
| 299 | DS1307_REG_HOUR, | ||
| 300 | BIN2BCD(tmp)); | ||
| 301 | } | ||
| 302 | |||
| 303 | /* FIXME chips like 1337 can generate alarm irqs too; those are | ||
| 304 | * worth exposing through the API (especially when the irq is | ||
| 305 | * wakeup-capable). | ||
| 306 | */ | ||
| 307 | |||
| 308 | switch (ds1307->type) { | 383 | switch (ds1307->type) { |
| 309 | case unknown: | ||
| 310 | strlcpy(client->name, "unknown", I2C_NAME_SIZE); | ||
| 311 | break; | ||
| 312 | case ds_1307: | ||
| 313 | strlcpy(client->name, "ds1307", I2C_NAME_SIZE); | ||
| 314 | break; | ||
| 315 | case ds_1337: | ||
| 316 | strlcpy(client->name, "ds1337", I2C_NAME_SIZE); | ||
| 317 | break; | ||
| 318 | case ds_1340: | 384 | case ds_1340: |
| 319 | strlcpy(client->name, "ds1340", I2C_NAME_SIZE); | 385 | case m41t00: |
| 386 | /* NOTE: ignores century bits; fix before deploying | ||
| 387 | * systems that will run through year 2100. | ||
| 388 | */ | ||
| 320 | break; | 389 | break; |
| 321 | } | 390 | default: |
| 391 | if (!(tmp & DS1307_BIT_12HR)) | ||
| 392 | break; | ||
| 322 | 393 | ||
| 323 | /* Tell the I2C layer a new client has arrived */ | 394 | /* Be sure we're in 24 hour mode. Multi-master systems |
| 324 | if ((err = i2c_attach_client(client))) | 395 | * take note... |
| 325 | goto exit_free; | 396 | */ |
| 397 | tmp = BCD2BIN(tmp & 0x1f); | ||
| 398 | if (tmp == 12) | ||
| 399 | tmp = 0; | ||
| 400 | if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM) | ||
| 401 | tmp += 12; | ||
| 402 | i2c_smbus_write_byte_data(client, | ||
| 403 | DS1307_REG_HOUR, | ||
| 404 | BIN2BCD(tmp)); | ||
| 405 | } | ||
| 326 | 406 | ||
| 327 | ds1307->rtc = rtc_device_register(client->name, &client->dev, | 407 | ds1307->rtc = rtc_device_register(client->name, &client->dev, |
| 328 | &ds13xx_rtc_ops, THIS_MODULE); | 408 | &ds13xx_rtc_ops, THIS_MODULE); |
| @@ -330,46 +410,40 @@ read_rtc: | |||
| 330 | err = PTR_ERR(ds1307->rtc); | 410 | err = PTR_ERR(ds1307->rtc); |
| 331 | dev_err(&client->dev, | 411 | dev_err(&client->dev, |
| 332 | "unable to register the class device\n"); | 412 | "unable to register the class device\n"); |
| 333 | goto exit_detach; | 413 | goto exit_free; |
| 334 | } | 414 | } |
| 335 | 415 | ||
| 336 | return 0; | 416 | return 0; |
| 337 | 417 | ||
| 338 | exit_detach: | 418 | exit_bad: |
| 339 | i2c_detach_client(client); | 419 | dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", |
| 420 | "bogus register", | ||
| 421 | ds1307->regs[0], ds1307->regs[1], | ||
| 422 | ds1307->regs[2], ds1307->regs[3], | ||
| 423 | ds1307->regs[4], ds1307->regs[5], | ||
| 424 | ds1307->regs[6]); | ||
| 425 | |||
| 340 | exit_free: | 426 | exit_free: |
| 341 | kfree(ds1307); | 427 | kfree(ds1307); |
| 342 | exit: | ||
| 343 | return err; | 428 | return err; |
| 344 | } | 429 | } |
| 345 | 430 | ||
| 346 | static int __devinit | 431 | static int __devexit ds1307_remove(struct i2c_client *client) |
| 347 | ds1307_attach_adapter(struct i2c_adapter *adapter) | ||
| 348 | { | ||
| 349 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) | ||
| 350 | return 0; | ||
| 351 | return i2c_probe(adapter, &addr_data, ds1307_detect); | ||
| 352 | } | ||
| 353 | |||
| 354 | static int __devexit ds1307_detach_client(struct i2c_client *client) | ||
| 355 | { | 432 | { |
| 356 | int err; | ||
| 357 | struct ds1307 *ds1307 = i2c_get_clientdata(client); | 433 | struct ds1307 *ds1307 = i2c_get_clientdata(client); |
| 358 | 434 | ||
| 359 | rtc_device_unregister(ds1307->rtc); | 435 | rtc_device_unregister(ds1307->rtc); |
| 360 | if ((err = i2c_detach_client(client))) | ||
| 361 | return err; | ||
| 362 | kfree(ds1307); | 436 | kfree(ds1307); |
| 363 | return 0; | 437 | return 0; |
| 364 | } | 438 | } |
| 365 | 439 | ||
| 366 | static struct i2c_driver ds1307_driver = { | 440 | static struct i2c_driver ds1307_driver = { |
| 367 | .driver = { | 441 | .driver = { |
| 368 | .name = "ds1307", | 442 | .name = "rtc-ds1307", |
| 369 | .owner = THIS_MODULE, | 443 | .owner = THIS_MODULE, |
| 370 | }, | 444 | }, |
| 371 | .attach_adapter = ds1307_attach_adapter, | 445 | .probe = ds1307_probe, |
| 372 | .detach_client = __devexit_p(ds1307_detach_client), | 446 | .remove = __devexit_p(ds1307_remove), |
| 373 | }; | 447 | }; |
| 374 | 448 | ||
| 375 | static int __init ds1307_init(void) | 449 | static int __init ds1307_init(void) |
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index f98a83a11aae..46da5714932c 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c | |||
| @@ -407,7 +407,7 @@ static __init int ds1553_init(void) | |||
| 407 | 407 | ||
| 408 | static __exit void ds1553_exit(void) | 408 | static __exit void ds1553_exit(void) |
| 409 | { | 409 | { |
| 410 | return platform_driver_unregister(&ds1553_rtc_driver); | 410 | platform_driver_unregister(&ds1553_rtc_driver); |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | module_init(ds1553_init); | 413 | module_init(ds1553_init); |
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index d1778ae8bca5..b2e5481ba3b6 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c | |||
| @@ -263,7 +263,7 @@ static __init int ds1742_init(void) | |||
| 263 | 263 | ||
| 264 | static __exit void ds1742_exit(void) | 264 | static __exit void ds1742_exit(void) |
| 265 | { | 265 | { |
| 266 | return platform_driver_unregister(&ds1742_rtc_driver); | 266 | platform_driver_unregister(&ds1742_rtc_driver); |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | module_init(ds1742_init); | 269 | module_init(ds1742_init); |
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c new file mode 100644 index 000000000000..80c4a8463065 --- /dev/null +++ b/drivers/rtc/rtc-m41t80.c | |||
| @@ -0,0 +1,917 @@ | |||
| 1 | /* | ||
| 2 | * I2C client/driver for the ST M41T80 family of i2c rtc chips. | ||
| 3 | * | ||
| 4 | * Author: Alexander Bigga <ab@mycable.de> | ||
| 5 | * | ||
| 6 | * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com> | ||
| 7 | * | ||
| 8 | * 2006 (c) mycable GmbH | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/string.h> | ||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include <linux/rtc.h> | ||
| 22 | #include <linux/bcd.h> | ||
| 23 | #ifdef CONFIG_RTC_DRV_M41T80_WDT | ||
| 24 | #include <linux/miscdevice.h> | ||
| 25 | #include <linux/watchdog.h> | ||
| 26 | #include <linux/reboot.h> | ||
| 27 | #include <linux/fs.h> | ||
| 28 | #include <linux/ioctl.h> | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #define M41T80_REG_SSEC 0 | ||
| 32 | #define M41T80_REG_SEC 1 | ||
| 33 | #define M41T80_REG_MIN 2 | ||
| 34 | #define M41T80_REG_HOUR 3 | ||
| 35 | #define M41T80_REG_WDAY 4 | ||
| 36 | #define M41T80_REG_DAY 5 | ||
| 37 | #define M41T80_REG_MON 6 | ||
| 38 | #define M41T80_REG_YEAR 7 | ||
| 39 | #define M41T80_REG_ALARM_MON 0xa | ||
| 40 | #define M41T80_REG_ALARM_DAY 0xb | ||
| 41 | #define M41T80_REG_ALARM_HOUR 0xc | ||
| 42 | #define M41T80_REG_ALARM_MIN 0xd | ||
| 43 | #define M41T80_REG_ALARM_SEC 0xe | ||
| 44 | #define M41T80_REG_FLAGS 0xf | ||
| 45 | #define M41T80_REG_SQW 0x13 | ||
| 46 | |||
| 47 | #define M41T80_DATETIME_REG_SIZE (M41T80_REG_YEAR + 1) | ||
| 48 | #define M41T80_ALARM_REG_SIZE \ | ||
| 49 | (M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON) | ||
| 50 | |||
| 51 | #define M41T80_SEC_ST (1 << 7) /* ST: Stop Bit */ | ||
| 52 | #define M41T80_ALMON_AFE (1 << 7) /* AFE: AF Enable Bit */ | ||
| 53 | #define M41T80_ALMON_SQWE (1 << 6) /* SQWE: SQW Enable Bit */ | ||
| 54 | #define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */ | ||
| 55 | #define M41T80_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */ | ||
| 56 | #define M41T80_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */ | ||
| 57 | |||
| 58 | #define M41T80_FEATURE_HT (1 << 0) | ||
| 59 | #define M41T80_FEATURE_BL (1 << 1) | ||
| 60 | |||
| 61 | #define DRV_VERSION "0.05" | ||
| 62 | |||
| 63 | struct m41t80_chip_info { | ||
| 64 | const char *name; | ||
| 65 | u8 features; | ||
| 66 | }; | ||
| 67 | |||
| 68 | static const struct m41t80_chip_info m41t80_chip_info_tbl[] = { | ||
| 69 | { | ||
| 70 | .name = "m41t80", | ||
| 71 | .features = 0, | ||
| 72 | }, | ||
| 73 | { | ||
| 74 | .name = "m41t81", | ||
| 75 | .features = M41T80_FEATURE_HT, | ||
| 76 | }, | ||
| 77 | { | ||
| 78 | .name = "m41t81s", | ||
| 79 | .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, | ||
| 80 | }, | ||
| 81 | { | ||
| 82 | .name = "m41t82", | ||
| 83 | .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, | ||
| 84 | }, | ||
| 85 | { | ||
| 86 | .name = "m41t83", | ||
| 87 | .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, | ||
| 88 | }, | ||
| 89 | { | ||
| 90 | .name = "m41st84", | ||
| 91 | .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, | ||
| 92 | }, | ||
| 93 | { | ||
| 94 | .name = "m41st85", | ||
| 95 | .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, | ||
| 96 | }, | ||
| 97 | { | ||
| 98 | .name = "m41st87", | ||
| 99 | .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, | ||
| 100 | }, | ||
| 101 | }; | ||
| 102 | |||
| 103 | struct m41t80_data { | ||
| 104 | const struct m41t80_chip_info *chip; | ||
| 105 | struct rtc_device *rtc; | ||
| 106 | }; | ||
| 107 | |||
| 108 | static int m41t80_get_datetime(struct i2c_client *client, | ||
| 109 | struct rtc_time *tm) | ||
| 110 | { | ||
| 111 | u8 buf[M41T80_DATETIME_REG_SIZE], dt_addr[1] = { M41T80_REG_SEC }; | ||
| 112 | struct i2c_msg msgs[] = { | ||
| 113 | { | ||
| 114 | .addr = client->addr, | ||
| 115 | .flags = 0, | ||
| 116 | .len = 1, | ||
| 117 | .buf = dt_addr, | ||
| 118 | }, | ||
| 119 | { | ||
| 120 | .addr = client->addr, | ||
| 121 | .flags = I2C_M_RD, | ||
| 122 | .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC, | ||
| 123 | .buf = buf + M41T80_REG_SEC, | ||
| 124 | }, | ||
| 125 | }; | ||
| 126 | |||
| 127 | if (i2c_transfer(client->adapter, msgs, 2) < 0) { | ||
| 128 | dev_err(&client->dev, "read error\n"); | ||
| 129 | return -EIO; | ||
| 130 | } | ||
| 131 | |||
| 132 | tm->tm_sec = BCD2BIN(buf[M41T80_REG_SEC] & 0x7f); | ||
| 133 | tm->tm_min = BCD2BIN(buf[M41T80_REG_MIN] & 0x7f); | ||
| 134 | tm->tm_hour = BCD2BIN(buf[M41T80_REG_HOUR] & 0x3f); | ||
| 135 | tm->tm_mday = BCD2BIN(buf[M41T80_REG_DAY] & 0x3f); | ||
| 136 | tm->tm_wday = buf[M41T80_REG_WDAY] & 0x07; | ||
| 137 | tm->tm_mon = BCD2BIN(buf[M41T80_REG_MON] & 0x1f) - 1; | ||
| 138 | |||
| 139 | /* assume 20YY not 19YY, and ignore the Century Bit */ | ||
| 140 | tm->tm_year = BCD2BIN(buf[M41T80_REG_YEAR]) + 100; | ||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | /* Sets the given date and time to the real time clock. */ | ||
| 145 | static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
| 146 | { | ||
| 147 | u8 wbuf[1 + M41T80_DATETIME_REG_SIZE]; | ||
| 148 | u8 *buf = &wbuf[1]; | ||
| 149 | u8 dt_addr[1] = { M41T80_REG_SEC }; | ||
| 150 | struct i2c_msg msgs_in[] = { | ||
| 151 | { | ||
| 152 | .addr = client->addr, | ||
| 153 | .flags = 0, | ||
| 154 | .len = 1, | ||
| 155 | .buf = dt_addr, | ||
| 156 | }, | ||
| 157 | { | ||
| 158 | .addr = client->addr, | ||
| 159 | .flags = I2C_M_RD, | ||
| 160 | .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC, | ||
| 161 | .buf = buf + M41T80_REG_SEC, | ||
| 162 | }, | ||
| 163 | }; | ||
| 164 | struct i2c_msg msgs[] = { | ||
| 165 | { | ||
| 166 | .addr = client->addr, | ||
| 167 | .flags = 0, | ||
| 168 | .len = 1 + M41T80_DATETIME_REG_SIZE, | ||
| 169 | .buf = wbuf, | ||
| 170 | }, | ||
| 171 | }; | ||
| 172 | |||
| 173 | /* Read current reg values into buf[1..7] */ | ||
| 174 | if (i2c_transfer(client->adapter, msgs_in, 2) < 0) { | ||
| 175 | dev_err(&client->dev, "read error\n"); | ||
| 176 | return -EIO; | ||
| 177 | } | ||
| 178 | |||
| 179 | wbuf[0] = 0; /* offset into rtc's regs */ | ||
| 180 | /* Merge time-data and register flags into buf[0..7] */ | ||
| 181 | buf[M41T80_REG_SSEC] = 0; | ||
| 182 | buf[M41T80_REG_SEC] = | ||
| 183 | BIN2BCD(tm->tm_sec) | (buf[M41T80_REG_SEC] & ~0x7f); | ||
| 184 | buf[M41T80_REG_MIN] = | ||
| 185 | BIN2BCD(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f); | ||
| 186 | buf[M41T80_REG_HOUR] = | ||
| 187 | BIN2BCD(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f) ; | ||
| 188 | buf[M41T80_REG_WDAY] = | ||
| 189 | (tm->tm_wday & 0x07) | (buf[M41T80_REG_WDAY] & ~0x07); | ||
| 190 | buf[M41T80_REG_DAY] = | ||
| 191 | BIN2BCD(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f); | ||
| 192 | buf[M41T80_REG_MON] = | ||
| 193 | BIN2BCD(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f); | ||
| 194 | /* assume 20YY not 19YY */ | ||
| 195 | buf[M41T80_REG_YEAR] = BIN2BCD(tm->tm_year % 100); | ||
| 196 | |||
| 197 | if (i2c_transfer(client->adapter, msgs, 1) != 1) { | ||
| 198 | dev_err(&client->dev, "write error\n"); | ||
| 199 | return -EIO; | ||
| 200 | } | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) | ||
| 205 | static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq) | ||
| 206 | { | ||
| 207 | struct i2c_client *client = to_i2c_client(dev); | ||
| 208 | struct m41t80_data *clientdata = i2c_get_clientdata(client); | ||
| 209 | u8 reg; | ||
| 210 | |||
| 211 | if (clientdata->chip->features & M41T80_FEATURE_BL) { | ||
| 212 | reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); | ||
| 213 | seq_printf(seq, "battery\t\t: %s\n", | ||
| 214 | (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok"); | ||
| 215 | } | ||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | #else | ||
| 219 | #define m41t80_rtc_proc NULL | ||
| 220 | #endif | ||
| 221 | |||
| 222 | static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 223 | { | ||
| 224 | return m41t80_get_datetime(to_i2c_client(dev), tm); | ||
| 225 | } | ||
| 226 | |||
| 227 | static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 228 | { | ||
| 229 | return m41t80_set_datetime(to_i2c_client(dev), tm); | ||
| 230 | } | ||
| 231 | |||
| 232 | #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) | ||
| 233 | static int | ||
| 234 | m41t80_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
| 235 | { | ||
| 236 | struct i2c_client *client = to_i2c_client(dev); | ||
| 237 | int rc; | ||
| 238 | |||
| 239 | switch (cmd) { | ||
| 240 | case RTC_AIE_OFF: | ||
| 241 | case RTC_AIE_ON: | ||
| 242 | break; | ||
| 243 | default: | ||
| 244 | return -ENOIOCTLCMD; | ||
| 245 | } | ||
| 246 | |||
| 247 | rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); | ||
| 248 | if (rc < 0) | ||
| 249 | goto err; | ||
| 250 | switch (cmd) { | ||
| 251 | case RTC_AIE_OFF: | ||
| 252 | rc &= ~M41T80_ALMON_AFE; | ||
| 253 | break; | ||
| 254 | case RTC_AIE_ON: | ||
| 255 | rc |= M41T80_ALMON_AFE; | ||
| 256 | break; | ||
| 257 | } | ||
| 258 | if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0) | ||
| 259 | goto err; | ||
| 260 | return 0; | ||
| 261 | err: | ||
| 262 | return -EIO; | ||
| 263 | } | ||
| 264 | #else | ||
| 265 | #define m41t80_rtc_ioctl NULL | ||
| 266 | #endif | ||
| 267 | |||
| 268 | static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) | ||
| 269 | { | ||
| 270 | struct i2c_client *client = to_i2c_client(dev); | ||
| 271 | u8 wbuf[1 + M41T80_ALARM_REG_SIZE]; | ||
| 272 | u8 *buf = &wbuf[1]; | ||
| 273 | u8 *reg = buf - M41T80_REG_ALARM_MON; | ||
| 274 | u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; | ||
| 275 | struct i2c_msg msgs_in[] = { | ||
| 276 | { | ||
| 277 | .addr = client->addr, | ||
| 278 | .flags = 0, | ||
| 279 | .len = 1, | ||
| 280 | .buf = dt_addr, | ||
| 281 | }, | ||
| 282 | { | ||
| 283 | .addr = client->addr, | ||
| 284 | .flags = I2C_M_RD, | ||
| 285 | .len = M41T80_ALARM_REG_SIZE, | ||
| 286 | .buf = buf, | ||
| 287 | }, | ||
| 288 | }; | ||
| 289 | struct i2c_msg msgs[] = { | ||
| 290 | { | ||
| 291 | .addr = client->addr, | ||
| 292 | .flags = 0, | ||
| 293 | .len = 1 + M41T80_ALARM_REG_SIZE, | ||
| 294 | .buf = wbuf, | ||
| 295 | }, | ||
| 296 | }; | ||
| 297 | |||
| 298 | if (i2c_transfer(client->adapter, msgs_in, 2) < 0) { | ||
| 299 | dev_err(&client->dev, "read error\n"); | ||
| 300 | return -EIO; | ||
| 301 | } | ||
| 302 | reg[M41T80_REG_ALARM_MON] &= ~(0x1f | M41T80_ALMON_AFE); | ||
| 303 | reg[M41T80_REG_ALARM_DAY] = 0; | ||
| 304 | reg[M41T80_REG_ALARM_HOUR] &= ~(0x3f | 0x80); | ||
| 305 | reg[M41T80_REG_ALARM_MIN] = 0; | ||
| 306 | reg[M41T80_REG_ALARM_SEC] = 0; | ||
| 307 | |||
| 308 | wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */ | ||
| 309 | reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ? | ||
| 310 | BIN2BCD(t->time.tm_sec) : 0x80; | ||
| 311 | reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ? | ||
| 312 | BIN2BCD(t->time.tm_min) : 0x80; | ||
| 313 | reg[M41T80_REG_ALARM_HOUR] |= t->time.tm_hour >= 0 ? | ||
| 314 | BIN2BCD(t->time.tm_hour) : 0x80; | ||
| 315 | reg[M41T80_REG_ALARM_DAY] |= t->time.tm_mday >= 0 ? | ||
| 316 | BIN2BCD(t->time.tm_mday) : 0x80; | ||
| 317 | if (t->time.tm_mon >= 0) | ||
| 318 | reg[M41T80_REG_ALARM_MON] |= BIN2BCD(t->time.tm_mon + 1); | ||
| 319 | else | ||
| 320 | reg[M41T80_REG_ALARM_DAY] |= 0x40; | ||
| 321 | |||
| 322 | if (i2c_transfer(client->adapter, msgs, 1) != 1) { | ||
| 323 | dev_err(&client->dev, "write error\n"); | ||
| 324 | return -EIO; | ||
| 325 | } | ||
| 326 | |||
| 327 | if (t->enabled) { | ||
| 328 | reg[M41T80_REG_ALARM_MON] |= M41T80_ALMON_AFE; | ||
| 329 | if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, | ||
| 330 | reg[M41T80_REG_ALARM_MON]) < 0) { | ||
| 331 | dev_err(&client->dev, "write error\n"); | ||
| 332 | return -EIO; | ||
| 333 | } | ||
| 334 | } | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) | ||
| 339 | { | ||
| 340 | struct i2c_client *client = to_i2c_client(dev); | ||
| 341 | u8 buf[M41T80_ALARM_REG_SIZE + 1]; /* all alarm regs and flags */ | ||
| 342 | u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; | ||
| 343 | u8 *reg = buf - M41T80_REG_ALARM_MON; | ||
| 344 | struct i2c_msg msgs[] = { | ||
| 345 | { | ||
| 346 | .addr = client->addr, | ||
| 347 | .flags = 0, | ||
| 348 | .len = 1, | ||
| 349 | .buf = dt_addr, | ||
| 350 | }, | ||
| 351 | { | ||
| 352 | .addr = client->addr, | ||
| 353 | .flags = I2C_M_RD, | ||
| 354 | .len = M41T80_ALARM_REG_SIZE + 1, | ||
| 355 | .buf = buf, | ||
| 356 | }, | ||
| 357 | }; | ||
| 358 | |||
| 359 | if (i2c_transfer(client->adapter, msgs, 2) < 0) { | ||
| 360 | dev_err(&client->dev, "read error\n"); | ||
| 361 | return -EIO; | ||
| 362 | } | ||
| 363 | t->time.tm_sec = -1; | ||
| 364 | t->time.tm_min = -1; | ||
| 365 | t->time.tm_hour = -1; | ||
| 366 | t->time.tm_mday = -1; | ||
| 367 | t->time.tm_mon = -1; | ||
| 368 | if (!(reg[M41T80_REG_ALARM_SEC] & 0x80)) | ||
| 369 | t->time.tm_sec = BCD2BIN(reg[M41T80_REG_ALARM_SEC] & 0x7f); | ||
| 370 | if (!(reg[M41T80_REG_ALARM_MIN] & 0x80)) | ||
| 371 | t->time.tm_min = BCD2BIN(reg[M41T80_REG_ALARM_MIN] & 0x7f); | ||
| 372 | if (!(reg[M41T80_REG_ALARM_HOUR] & 0x80)) | ||
| 373 | t->time.tm_hour = BCD2BIN(reg[M41T80_REG_ALARM_HOUR] & 0x3f); | ||
| 374 | if (!(reg[M41T80_REG_ALARM_DAY] & 0x80)) | ||
| 375 | t->time.tm_mday = BCD2BIN(reg[M41T80_REG_ALARM_DAY] & 0x3f); | ||
| 376 | if (!(reg[M41T80_REG_ALARM_DAY] & 0x40)) | ||
| 377 | t->time.tm_mon = BCD2BIN(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1; | ||
| 378 | t->time.tm_year = -1; | ||
| 379 | t->time.tm_wday = -1; | ||
| 380 | t->time.tm_yday = -1; | ||
| 381 | t->time.tm_isdst = -1; | ||
| 382 | t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE); | ||
| 383 | t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF); | ||
| 384 | return 0; | ||
| 385 | } | ||
| 386 | |||
| 387 | static struct rtc_class_ops m41t80_rtc_ops = { | ||
| 388 | .read_time = m41t80_rtc_read_time, | ||
| 389 | .set_time = m41t80_rtc_set_time, | ||
| 390 | .read_alarm = m41t80_rtc_read_alarm, | ||
| 391 | .set_alarm = m41t80_rtc_set_alarm, | ||
| 392 | .proc = m41t80_rtc_proc, | ||
| 393 | .ioctl = m41t80_rtc_ioctl, | ||
| 394 | }; | ||
| 395 | |||
| 396 | #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) | ||
| 397 | static ssize_t m41t80_sysfs_show_flags(struct device *dev, | ||
| 398 | struct device_attribute *attr, char *buf) | ||
| 399 | { | ||
| 400 | struct i2c_client *client = to_i2c_client(dev); | ||
| 401 | int val; | ||
| 402 | |||
| 403 | val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); | ||
| 404 | if (val < 0) | ||
| 405 | return -EIO; | ||
| 406 | return sprintf(buf, "%#x\n", val); | ||
| 407 | } | ||
| 408 | static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL); | ||
| 409 | |||
| 410 | static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev, | ||
| 411 | struct device_attribute *attr, char *buf) | ||
| 412 | { | ||
| 413 | struct i2c_client *client = to_i2c_client(dev); | ||
| 414 | int val; | ||
| 415 | |||
| 416 | val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); | ||
| 417 | if (val < 0) | ||
| 418 | return -EIO; | ||
| 419 | val = (val >> 4) & 0xf; | ||
| 420 | switch (val) { | ||
| 421 | case 0: | ||
| 422 | break; | ||
| 423 | case 1: | ||
| 424 | val = 32768; | ||
| 425 | break; | ||
| 426 | default: | ||
| 427 | val = 32768 >> val; | ||
| 428 | } | ||
| 429 | return sprintf(buf, "%d\n", val); | ||
| 430 | } | ||
| 431 | static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, | ||
| 432 | struct device_attribute *attr, | ||
| 433 | const char *buf, size_t count) | ||
| 434 | { | ||
| 435 | struct i2c_client *client = to_i2c_client(dev); | ||
| 436 | int almon, sqw; | ||
| 437 | int val = simple_strtoul(buf, NULL, 0); | ||
| 438 | |||
| 439 | if (val) { | ||
| 440 | if (!is_power_of_2(val)) | ||
| 441 | return -EINVAL; | ||
| 442 | val = ilog2(val); | ||
| 443 | if (val == 15) | ||
| 444 | val = 1; | ||
| 445 | else if (val < 14) | ||
| 446 | val = 15 - val; | ||
| 447 | else | ||
| 448 | return -EINVAL; | ||
| 449 | } | ||
| 450 | /* disable SQW, set SQW frequency & re-enable */ | ||
| 451 | almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); | ||
| 452 | if (almon < 0) | ||
| 453 | return -EIO; | ||
| 454 | sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); | ||
| 455 | if (sqw < 0) | ||
| 456 | return -EIO; | ||
| 457 | sqw = (sqw & 0x0f) | (val << 4); | ||
| 458 | if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, | ||
| 459 | almon & ~M41T80_ALMON_SQWE) < 0 || | ||
| 460 | i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0) | ||
| 461 | return -EIO; | ||
| 462 | if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, | ||
| 463 | almon | M41T80_ALMON_SQWE) < 0) | ||
| 464 | return -EIO; | ||
| 465 | return count; | ||
| 466 | } | ||
| 467 | static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR, | ||
| 468 | m41t80_sysfs_show_sqwfreq, m41t80_sysfs_set_sqwfreq); | ||
| 469 | |||
| 470 | static struct attribute *attrs[] = { | ||
| 471 | &dev_attr_flags.attr, | ||
| 472 | &dev_attr_sqwfreq.attr, | ||
| 473 | NULL, | ||
| 474 | }; | ||
| 475 | static struct attribute_group attr_group = { | ||
| 476 | .attrs = attrs, | ||
| 477 | }; | ||
| 478 | |||
| 479 | static int m41t80_sysfs_register(struct device *dev) | ||
| 480 | { | ||
| 481 | return sysfs_create_group(&dev->kobj, &attr_group); | ||
| 482 | } | ||
| 483 | #else | ||
| 484 | static int m41t80_sysfs_register(struct device *dev) | ||
| 485 | { | ||
| 486 | return 0; | ||
| 487 | } | ||
| 488 | #endif | ||
| 489 | |||
| 490 | #ifdef CONFIG_RTC_DRV_M41T80_WDT | ||
| 491 | /* | ||
| 492 | ***************************************************************************** | ||
| 493 | * | ||
| 494 | * Watchdog Driver | ||
| 495 | * | ||
| 496 | ***************************************************************************** | ||
| 497 | */ | ||
| 498 | static struct i2c_client *save_client; | ||
| 499 | |||
| 500 | /* Default margin */ | ||
| 501 | #define WD_TIMO 60 /* 1..31 seconds */ | ||
| 502 | |||
| 503 | static int wdt_margin = WD_TIMO; | ||
| 504 | module_param(wdt_margin, int, 0); | ||
| 505 | MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 60s)"); | ||
| 506 | |||
| 507 | static unsigned long wdt_is_open; | ||
| 508 | static int boot_flag; | ||
| 509 | |||
| 510 | /** | ||
| 511 | * wdt_ping: | ||
| 512 | * | ||
| 513 | * Reload counter one with the watchdog timeout. We don't bother reloading | ||
| 514 | * the cascade counter. | ||
| 515 | */ | ||
| 516 | static void wdt_ping(void) | ||
| 517 | { | ||
| 518 | unsigned char i2c_data[2]; | ||
| 519 | struct i2c_msg msgs1[1] = { | ||
| 520 | { | ||
| 521 | .addr = save_client->addr, | ||
| 522 | .flags = 0, | ||
| 523 | .len = 2, | ||
| 524 | .buf = i2c_data, | ||
| 525 | }, | ||
| 526 | }; | ||
| 527 | i2c_data[0] = 0x09; /* watchdog register */ | ||
| 528 | |||
| 529 | if (wdt_margin > 31) | ||
| 530 | i2c_data[1] = (wdt_margin & 0xFC) | 0x83; /* resolution = 4s */ | ||
| 531 | else | ||
| 532 | /* | ||
| 533 | * WDS = 1 (0x80), mulitplier = WD_TIMO, resolution = 1s (0x02) | ||
| 534 | */ | ||
| 535 | i2c_data[1] = wdt_margin<<2 | 0x82; | ||
| 536 | |||
| 537 | i2c_transfer(save_client->adapter, msgs1, 1); | ||
| 538 | } | ||
| 539 | |||
| 540 | /** | ||
| 541 | * wdt_disable: | ||
| 542 | * | ||
| 543 | * disables watchdog. | ||
| 544 | */ | ||
| 545 | static void wdt_disable(void) | ||
| 546 | { | ||
| 547 | unsigned char i2c_data[2], i2c_buf[0x10]; | ||
| 548 | struct i2c_msg msgs0[2] = { | ||
| 549 | { | ||
| 550 | .addr = save_client->addr, | ||
| 551 | .flags = 0, | ||
| 552 | .len = 1, | ||
| 553 | .buf = i2c_data, | ||
| 554 | }, | ||
| 555 | { | ||
| 556 | .addr = save_client->addr, | ||
| 557 | .flags = I2C_M_RD, | ||
| 558 | .len = 1, | ||
| 559 | .buf = i2c_buf, | ||
| 560 | }, | ||
| 561 | }; | ||
| 562 | struct i2c_msg msgs1[1] = { | ||
| 563 | { | ||
| 564 | .addr = save_client->addr, | ||
| 565 | .flags = 0, | ||
| 566 | .len = 2, | ||
| 567 | .buf = i2c_data, | ||
| 568 | }, | ||
| 569 | }; | ||
| 570 | |||
| 571 | i2c_data[0] = 0x09; | ||
| 572 | i2c_transfer(save_client->adapter, msgs0, 2); | ||
| 573 | |||
| 574 | i2c_data[0] = 0x09; | ||
| 575 | i2c_data[1] = 0x00; | ||
| 576 | i2c_transfer(save_client->adapter, msgs1, 1); | ||
| 577 | } | ||
| 578 | |||
| 579 | /** | ||
| 580 | * wdt_write: | ||
| 581 | * @file: file handle to the watchdog | ||
| 582 | * @buf: buffer to write (unused as data does not matter here | ||
| 583 | * @count: count of bytes | ||
| 584 | * @ppos: pointer to the position to write. No seeks allowed | ||
| 585 | * | ||
| 586 | * A write to a watchdog device is defined as a keepalive signal. Any | ||
| 587 | * write of data will do, as we we don't define content meaning. | ||
| 588 | */ | ||
| 589 | static ssize_t wdt_write(struct file *file, const char __user *buf, | ||
| 590 | size_t count, loff_t *ppos) | ||
| 591 | { | ||
| 592 | /* Can't seek (pwrite) on this device | ||
| 593 | if (ppos != &file->f_pos) | ||
| 594 | return -ESPIPE; | ||
| 595 | */ | ||
| 596 | if (count) { | ||
| 597 | wdt_ping(); | ||
| 598 | return 1; | ||
| 599 | } | ||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 603 | static ssize_t wdt_read(struct file *file, char __user *buf, | ||
| 604 | size_t count, loff_t *ppos) | ||
| 605 | { | ||
| 606 | return 0; | ||
| 607 | } | ||
| 608 | |||
| 609 | /** | ||
| 610 | * wdt_ioctl: | ||
| 611 | * @inode: inode of the device | ||
| 612 | * @file: file handle to the device | ||
| 613 | * @cmd: watchdog command | ||
| 614 | * @arg: argument pointer | ||
| 615 | * | ||
| 616 | * The watchdog API defines a common set of functions for all watchdogs | ||
| 617 | * according to their available features. We only actually usefully support | ||
| 618 | * querying capabilities and current status. | ||
| 619 | */ | ||
| 620 | static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
| 621 | unsigned long arg) | ||
| 622 | { | ||
| 623 | int new_margin, rv; | ||
| 624 | static struct watchdog_info ident = { | ||
| 625 | .options = WDIOF_POWERUNDER | WDIOF_KEEPALIVEPING | | ||
| 626 | WDIOF_SETTIMEOUT, | ||
| 627 | .firmware_version = 1, | ||
| 628 | .identity = "M41T80 WTD" | ||
| 629 | }; | ||
| 630 | |||
| 631 | switch (cmd) { | ||
| 632 | case WDIOC_GETSUPPORT: | ||
| 633 | return copy_to_user((struct watchdog_info __user *)arg, &ident, | ||
| 634 | sizeof(ident)) ? -EFAULT : 0; | ||
| 635 | |||
| 636 | case WDIOC_GETSTATUS: | ||
| 637 | case WDIOC_GETBOOTSTATUS: | ||
| 638 | return put_user(boot_flag, (int __user *)arg); | ||
| 639 | case WDIOC_KEEPALIVE: | ||
| 640 | wdt_ping(); | ||
| 641 | return 0; | ||
| 642 | case WDIOC_SETTIMEOUT: | ||
| 643 | if (get_user(new_margin, (int __user *)arg)) | ||
| 644 | return -EFAULT; | ||
| 645 | /* Arbitrary, can't find the card's limits */ | ||
| 646 | if (new_margin < 1 || new_margin > 124) | ||
| 647 | return -EINVAL; | ||
| 648 | wdt_margin = new_margin; | ||
| 649 | wdt_ping(); | ||
| 650 | /* Fall */ | ||
| 651 | case WDIOC_GETTIMEOUT: | ||
| 652 | return put_user(wdt_margin, (int __user *)arg); | ||
| 653 | |||
| 654 | case WDIOC_SETOPTIONS: | ||
| 655 | if (copy_from_user(&rv, (int __user *)arg, sizeof(int))) | ||
| 656 | return -EFAULT; | ||
| 657 | |||
| 658 | if (rv & WDIOS_DISABLECARD) { | ||
| 659 | printk(KERN_INFO | ||
| 660 | "rtc-m41t80: disable watchdog\n"); | ||
| 661 | wdt_disable(); | ||
| 662 | } | ||
| 663 | |||
| 664 | if (rv & WDIOS_ENABLECARD) { | ||
| 665 | printk(KERN_INFO | ||
| 666 | "rtc-m41t80: enable watchdog\n"); | ||
| 667 | wdt_ping(); | ||
| 668 | } | ||
| 669 | |||
| 670 | return -EINVAL; | ||
| 671 | } | ||
| 672 | return -ENOTTY; | ||
| 673 | } | ||
| 674 | |||
| 675 | /** | ||
| 676 | * wdt_open: | ||
| 677 | * @inode: inode of device | ||
| 678 | * @file: file handle to device | ||
| 679 | * | ||
| 680 | */ | ||
| 681 | static int wdt_open(struct inode *inode, struct file *file) | ||
| 682 | { | ||
| 683 | if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { | ||
| 684 | if (test_and_set_bit(0, &wdt_is_open)) | ||
| 685 | return -EBUSY; | ||
| 686 | /* | ||
| 687 | * Activate | ||
| 688 | */ | ||
| 689 | wdt_is_open = 1; | ||
| 690 | return 0; | ||
| 691 | } | ||
| 692 | return -ENODEV; | ||
| 693 | } | ||
| 694 | |||
| 695 | /** | ||
| 696 | * wdt_close: | ||
| 697 | * @inode: inode to board | ||
| 698 | * @file: file handle to board | ||
| 699 | * | ||
| 700 | */ | ||
| 701 | static int wdt_release(struct inode *inode, struct file *file) | ||
| 702 | { | ||
| 703 | if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) | ||
| 704 | clear_bit(0, &wdt_is_open); | ||
| 705 | return 0; | ||
| 706 | } | ||
| 707 | |||
| 708 | /** | ||
| 709 | * notify_sys: | ||
| 710 | * @this: our notifier block | ||
| 711 | * @code: the event being reported | ||
| 712 | * @unused: unused | ||
| 713 | * | ||
| 714 | * Our notifier is called on system shutdowns. We want to turn the card | ||
| 715 | * off at reboot otherwise the machine will reboot again during memory | ||
| 716 | * test or worse yet during the following fsck. This would suck, in fact | ||
| 717 | * trust me - if it happens it does suck. | ||
| 718 | */ | ||
| 719 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
| 720 | void *unused) | ||
| 721 | { | ||
| 722 | if (code == SYS_DOWN || code == SYS_HALT) | ||
| 723 | /* Disable Watchdog */ | ||
| 724 | wdt_disable(); | ||
| 725 | return NOTIFY_DONE; | ||
| 726 | } | ||
| 727 | |||
| 728 | static const struct file_operations wdt_fops = { | ||
| 729 | .owner = THIS_MODULE, | ||
| 730 | .read = wdt_read, | ||
| 731 | .ioctl = wdt_ioctl, | ||
| 732 | .write = wdt_write, | ||
| 733 | .open = wdt_open, | ||
| 734 | .release = wdt_release, | ||
| 735 | }; | ||
| 736 | |||
| 737 | static struct miscdevice wdt_dev = { | ||
| 738 | .minor = WATCHDOG_MINOR, | ||
| 739 | .name = "watchdog", | ||
| 740 | .fops = &wdt_fops, | ||
| 741 | }; | ||
| 742 | |||
| 743 | /* | ||
| 744 | * The WDT card needs to learn about soft shutdowns in order to | ||
| 745 | * turn the timebomb registers off. | ||
| 746 | */ | ||
| 747 | static struct notifier_block wdt_notifier = { | ||
| 748 | .notifier_call = wdt_notify_sys, | ||
| 749 | }; | ||
| 750 | #endif /* CONFIG_RTC_DRV_M41T80_WDT */ | ||
| 751 | |||
| 752 | /* | ||
| 753 | ***************************************************************************** | ||
| 754 | * | ||
| 755 | * Driver Interface | ||
| 756 | * | ||
| 757 | ***************************************************************************** | ||
| 758 | */ | ||
| 759 | static int m41t80_probe(struct i2c_client *client) | ||
| 760 | { | ||
| 761 | int i, rc = 0; | ||
| 762 | struct rtc_device *rtc = NULL; | ||
| 763 | struct rtc_time tm; | ||
| 764 | const struct m41t80_chip_info *chip; | ||
| 765 | struct m41t80_data *clientdata = NULL; | ||
| 766 | |||
| 767 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | ||
| 768 | | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
| 769 | rc = -ENODEV; | ||
| 770 | goto exit; | ||
| 771 | } | ||
| 772 | |||
| 773 | dev_info(&client->dev, | ||
| 774 | "chip found, driver version " DRV_VERSION "\n"); | ||
| 775 | |||
| 776 | chip = NULL; | ||
| 777 | for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) { | ||
| 778 | if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) { | ||
| 779 | chip = &m41t80_chip_info_tbl[i]; | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | } | ||
| 783 | if (!chip) { | ||
| 784 | dev_err(&client->dev, "%s is not supported\n", client->name); | ||
| 785 | rc = -ENODEV; | ||
| 786 | goto exit; | ||
| 787 | } | ||
| 788 | |||
| 789 | clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL); | ||
| 790 | if (!clientdata) { | ||
| 791 | rc = -ENOMEM; | ||
| 792 | goto exit; | ||
| 793 | } | ||
| 794 | |||
| 795 | rtc = rtc_device_register(client->name, &client->dev, | ||
| 796 | &m41t80_rtc_ops, THIS_MODULE); | ||
| 797 | if (IS_ERR(rtc)) { | ||
| 798 | rc = PTR_ERR(rtc); | ||
| 799 | rtc = NULL; | ||
| 800 | goto exit; | ||
| 801 | } | ||
| 802 | |||
| 803 | clientdata->rtc = rtc; | ||
| 804 | clientdata->chip = chip; | ||
| 805 | i2c_set_clientdata(client, clientdata); | ||
| 806 | |||
| 807 | /* Make sure HT (Halt Update) bit is cleared */ | ||
| 808 | rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); | ||
| 809 | if (rc < 0) | ||
| 810 | goto ht_err; | ||
| 811 | |||
| 812 | if (rc & M41T80_ALHOUR_HT) { | ||
| 813 | if (chip->features & M41T80_FEATURE_HT) { | ||
| 814 | m41t80_get_datetime(client, &tm); | ||
| 815 | dev_info(&client->dev, "HT bit was set!\n"); | ||
| 816 | dev_info(&client->dev, | ||
| 817 | "Power Down at " | ||
| 818 | "%04i-%02i-%02i %02i:%02i:%02i\n", | ||
| 819 | tm.tm_year + 1900, | ||
| 820 | tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, | ||
| 821 | tm.tm_min, tm.tm_sec); | ||
| 822 | } | ||
| 823 | if (i2c_smbus_write_byte_data(client, | ||
| 824 | M41T80_REG_ALARM_HOUR, | ||
| 825 | rc & ~M41T80_ALHOUR_HT) < 0) | ||
| 826 | goto ht_err; | ||
| 827 | } | ||
| 828 | |||
| 829 | /* Make sure ST (stop) bit is cleared */ | ||
| 830 | rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC); | ||
| 831 | if (rc < 0) | ||
| 832 | goto st_err; | ||
| 833 | |||
| 834 | if (rc & M41T80_SEC_ST) { | ||
| 835 | if (i2c_smbus_write_byte_data(client, M41T80_REG_SEC, | ||
| 836 | rc & ~M41T80_SEC_ST) < 0) | ||
| 837 | goto st_err; | ||
| 838 | } | ||
| 839 | |||
| 840 | rc = m41t80_sysfs_register(&client->dev); | ||
| 841 | if (rc) | ||
| 842 | goto exit; | ||
| 843 | |||
| 844 | #ifdef CONFIG_RTC_DRV_M41T80_WDT | ||
| 845 | if (chip->features & M41T80_FEATURE_HT) { | ||
| 846 | rc = misc_register(&wdt_dev); | ||
| 847 | if (rc) | ||
| 848 | goto exit; | ||
| 849 | rc = register_reboot_notifier(&wdt_notifier); | ||
| 850 | if (rc) { | ||
| 851 | misc_deregister(&wdt_dev); | ||
| 852 | goto exit; | ||
| 853 | } | ||
| 854 | save_client = client; | ||
| 855 | } | ||
| 856 | #endif | ||
| 857 | return 0; | ||
| 858 | |||
| 859 | st_err: | ||
| 860 | rc = -EIO; | ||
| 861 | dev_err(&client->dev, "Can't clear ST bit\n"); | ||
| 862 | goto exit; | ||
| 863 | ht_err: | ||
| 864 | rc = -EIO; | ||
| 865 | dev_err(&client->dev, "Can't clear HT bit\n"); | ||
| 866 | goto exit; | ||
| 867 | |||
| 868 | exit: | ||
| 869 | if (rtc) | ||
| 870 | rtc_device_unregister(rtc); | ||
| 871 | kfree(clientdata); | ||
| 872 | return rc; | ||
| 873 | } | ||
| 874 | |||
| 875 | static int m41t80_remove(struct i2c_client *client) | ||
| 876 | { | ||
| 877 | struct m41t80_data *clientdata = i2c_get_clientdata(client); | ||
| 878 | struct rtc_device *rtc = clientdata->rtc; | ||
| 879 | |||
| 880 | #ifdef CONFIG_RTC_DRV_M41T80_WDT | ||
| 881 | if (clientdata->chip->features & M41T80_FEATURE_HT) { | ||
| 882 | misc_deregister(&wdt_dev); | ||
| 883 | unregister_reboot_notifier(&wdt_notifier); | ||
| 884 | } | ||
| 885 | #endif | ||
| 886 | if (rtc) | ||
| 887 | rtc_device_unregister(rtc); | ||
| 888 | kfree(clientdata); | ||
| 889 | |||
| 890 | return 0; | ||
| 891 | } | ||
| 892 | |||
| 893 | static struct i2c_driver m41t80_driver = { | ||
| 894 | .driver = { | ||
| 895 | .name = "m41t80", | ||
| 896 | }, | ||
| 897 | .probe = m41t80_probe, | ||
| 898 | .remove = m41t80_remove, | ||
| 899 | }; | ||
| 900 | |||
| 901 | static int __init m41t80_rtc_init(void) | ||
| 902 | { | ||
| 903 | return i2c_add_driver(&m41t80_driver); | ||
| 904 | } | ||
| 905 | |||
| 906 | static void __exit m41t80_rtc_exit(void) | ||
| 907 | { | ||
| 908 | i2c_del_driver(&m41t80_driver); | ||
| 909 | } | ||
| 910 | |||
| 911 | MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>"); | ||
| 912 | MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver"); | ||
| 913 | MODULE_LICENSE("GPL"); | ||
| 914 | MODULE_VERSION(DRV_VERSION); | ||
| 915 | |||
| 916 | module_init(m41t80_rtc_init); | ||
| 917 | module_exit(m41t80_rtc_exit); | ||
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c new file mode 100644 index 000000000000..33b752350ab5 --- /dev/null +++ b/drivers/rtc/rtc-m48t59.c | |||
| @@ -0,0 +1,491 @@ | |||
| 1 | /* | ||
| 2 | * ST M48T59 RTC driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2007 Wind River Systems, Inc. | ||
| 5 | * | ||
| 6 | * Author: Mark Zhan <rongkai.zhan@windriver.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/rtc.h> | ||
| 20 | #include <linux/rtc/m48t59.h> | ||
| 21 | #include <linux/bcd.h> | ||
| 22 | |||
| 23 | #ifndef NO_IRQ | ||
| 24 | #define NO_IRQ (-1) | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #define M48T59_READ(reg) pdata->read_byte(dev, reg) | ||
| 28 | #define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val) | ||
| 29 | |||
| 30 | #define M48T59_SET_BITS(mask, reg) \ | ||
| 31 | M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg)) | ||
| 32 | #define M48T59_CLEAR_BITS(mask, reg) \ | ||
| 33 | M48T59_WRITE((M48T59_READ(reg) & ~(mask)), (reg)) | ||
| 34 | |||
| 35 | struct m48t59_private { | ||
| 36 | void __iomem *ioaddr; | ||
| 37 | unsigned int size; /* iomem size */ | ||
| 38 | unsigned int irq; | ||
| 39 | struct rtc_device *rtc; | ||
| 40 | spinlock_t lock; /* serialize the NVRAM and RTC access */ | ||
| 41 | }; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * This is the generic access method when the chip is memory-mapped | ||
| 45 | */ | ||
| 46 | static void | ||
| 47 | m48t59_mem_writeb(struct device *dev, u32 ofs, u8 val) | ||
| 48 | { | ||
| 49 | struct platform_device *pdev = to_platform_device(dev); | ||
| 50 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 51 | |||
| 52 | writeb(val, m48t59->ioaddr+ofs); | ||
| 53 | } | ||
| 54 | |||
| 55 | static u8 | ||
| 56 | m48t59_mem_readb(struct device *dev, u32 ofs) | ||
| 57 | { | ||
| 58 | struct platform_device *pdev = to_platform_device(dev); | ||
| 59 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 60 | |||
| 61 | return readb(m48t59->ioaddr+ofs); | ||
| 62 | } | ||
| 63 | |||
| 64 | /* | ||
| 65 | * NOTE: M48T59 only uses BCD mode | ||
| 66 | */ | ||
| 67 | static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 68 | { | ||
| 69 | struct platform_device *pdev = to_platform_device(dev); | ||
| 70 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 71 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 72 | unsigned long flags; | ||
| 73 | u8 val; | ||
| 74 | |||
| 75 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 76 | /* Issue the READ command */ | ||
| 77 | M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); | ||
| 78 | |||
| 79 | tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR)); | ||
| 80 | /* tm_mon is 0-11 */ | ||
| 81 | tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1; | ||
| 82 | tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY)); | ||
| 83 | |||
| 84 | val = M48T59_READ(M48T59_WDAY); | ||
| 85 | if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { | ||
| 86 | dev_dbg(dev, "Century bit is enabled\n"); | ||
| 87 | tm->tm_year += 100; /* one century */ | ||
| 88 | } | ||
| 89 | |||
| 90 | tm->tm_wday = BCD2BIN(val & 0x07); | ||
| 91 | tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_HOUR) & 0x3F); | ||
| 92 | tm->tm_min = BCD2BIN(M48T59_READ(M48T59_MIN) & 0x7F); | ||
| 93 | tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_SEC) & 0x7F); | ||
| 94 | |||
| 95 | /* Clear the READ bit */ | ||
| 96 | M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); | ||
| 97 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 98 | |||
| 99 | dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n", | ||
| 100 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, | ||
| 101 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 106 | { | ||
| 107 | struct platform_device *pdev = to_platform_device(dev); | ||
| 108 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 109 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 110 | unsigned long flags; | ||
| 111 | u8 val = 0; | ||
| 112 | |||
| 113 | dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n", | ||
| 114 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, | ||
| 115 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
| 116 | |||
| 117 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 118 | /* Issue the WRITE command */ | ||
| 119 | M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); | ||
| 120 | |||
| 121 | M48T59_WRITE((BIN2BCD(tm->tm_sec) & 0x7F), M48T59_SEC); | ||
| 122 | M48T59_WRITE((BIN2BCD(tm->tm_min) & 0x7F), M48T59_MIN); | ||
| 123 | M48T59_WRITE((BIN2BCD(tm->tm_hour) & 0x3F), M48T59_HOUR); | ||
| 124 | M48T59_WRITE((BIN2BCD(tm->tm_mday) & 0x3F), M48T59_MDAY); | ||
| 125 | /* tm_mon is 0-11 */ | ||
| 126 | M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH); | ||
| 127 | M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR); | ||
| 128 | |||
| 129 | if (tm->tm_year/100) | ||
| 130 | val = (M48T59_WDAY_CEB | M48T59_WDAY_CB); | ||
| 131 | val |= (BIN2BCD(tm->tm_wday) & 0x07); | ||
| 132 | M48T59_WRITE(val, M48T59_WDAY); | ||
| 133 | |||
| 134 | /* Clear the WRITE bit */ | ||
| 135 | M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); | ||
| 136 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | /* | ||
| 141 | * Read alarm time and date in RTC | ||
| 142 | */ | ||
| 143 | static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 144 | { | ||
| 145 | struct platform_device *pdev = to_platform_device(dev); | ||
| 146 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 147 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 148 | struct rtc_time *tm = &alrm->time; | ||
| 149 | unsigned long flags; | ||
| 150 | u8 val; | ||
| 151 | |||
| 152 | /* If no irq, we don't support ALARM */ | ||
| 153 | if (m48t59->irq == NO_IRQ) | ||
| 154 | return -EIO; | ||
| 155 | |||
| 156 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 157 | /* Issue the READ command */ | ||
| 158 | M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); | ||
| 159 | |||
| 160 | tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR)); | ||
| 161 | /* tm_mon is 0-11 */ | ||
| 162 | tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1; | ||
| 163 | |||
| 164 | val = M48T59_READ(M48T59_WDAY); | ||
| 165 | if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) | ||
| 166 | tm->tm_year += 100; /* one century */ | ||
| 167 | |||
| 168 | tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_ALARM_DATE)); | ||
| 169 | tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_ALARM_HOUR)); | ||
| 170 | tm->tm_min = BCD2BIN(M48T59_READ(M48T59_ALARM_MIN)); | ||
| 171 | tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_ALARM_SEC)); | ||
| 172 | |||
| 173 | /* Clear the READ bit */ | ||
| 174 | M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); | ||
| 175 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 176 | |||
| 177 | dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n", | ||
| 178 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, | ||
| 179 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
| 180 | return 0; | ||
| 181 | } | ||
| 182 | |||
| 183 | /* | ||
| 184 | * Set alarm time and date in RTC | ||
| 185 | */ | ||
| 186 | static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 187 | { | ||
| 188 | struct platform_device *pdev = to_platform_device(dev); | ||
| 189 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 190 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 191 | struct rtc_time *tm = &alrm->time; | ||
| 192 | u8 mday, hour, min, sec; | ||
| 193 | unsigned long flags; | ||
| 194 | |||
| 195 | /* If no irq, we don't support ALARM */ | ||
| 196 | if (m48t59->irq == NO_IRQ) | ||
| 197 | return -EIO; | ||
| 198 | |||
| 199 | /* | ||
| 200 | * 0xff means "always match" | ||
| 201 | */ | ||
| 202 | mday = tm->tm_mday; | ||
| 203 | mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff; | ||
| 204 | if (mday == 0xff) | ||
| 205 | mday = M48T59_READ(M48T59_MDAY); | ||
| 206 | |||
| 207 | hour = tm->tm_hour; | ||
| 208 | hour = (hour < 24) ? BIN2BCD(hour) : 0x00; | ||
| 209 | |||
| 210 | min = tm->tm_min; | ||
| 211 | min = (min < 60) ? BIN2BCD(min) : 0x00; | ||
| 212 | |||
| 213 | sec = tm->tm_sec; | ||
| 214 | sec = (sec < 60) ? BIN2BCD(sec) : 0x00; | ||
| 215 | |||
| 216 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 217 | /* Issue the WRITE command */ | ||
| 218 | M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); | ||
| 219 | |||
| 220 | M48T59_WRITE(mday, M48T59_ALARM_DATE); | ||
| 221 | M48T59_WRITE(hour, M48T59_ALARM_HOUR); | ||
| 222 | M48T59_WRITE(min, M48T59_ALARM_MIN); | ||
| 223 | M48T59_WRITE(sec, M48T59_ALARM_SEC); | ||
| 224 | |||
| 225 | /* Clear the WRITE bit */ | ||
| 226 | M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); | ||
| 227 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 228 | |||
| 229 | dev_dbg(dev, "RTC set alarm time %04d-%02d-%02d %02d/%02d/%02d\n", | ||
| 230 | tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, | ||
| 231 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | /* | ||
| 236 | * Handle commands from user-space | ||
| 237 | */ | ||
| 238 | static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
| 239 | unsigned long arg) | ||
| 240 | { | ||
| 241 | struct platform_device *pdev = to_platform_device(dev); | ||
| 242 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 243 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 244 | unsigned long flags; | ||
| 245 | int ret = 0; | ||
| 246 | |||
| 247 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 248 | switch (cmd) { | ||
| 249 | case RTC_AIE_OFF: /* alarm interrupt off */ | ||
| 250 | M48T59_WRITE(0x00, M48T59_INTR); | ||
| 251 | break; | ||
| 252 | case RTC_AIE_ON: /* alarm interrupt on */ | ||
| 253 | M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR); | ||
| 254 | break; | ||
| 255 | default: | ||
| 256 | ret = -ENOIOCTLCMD; | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 260 | |||
| 261 | return ret; | ||
| 262 | } | ||
| 263 | |||
| 264 | static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq) | ||
| 265 | { | ||
| 266 | struct platform_device *pdev = to_platform_device(dev); | ||
| 267 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 268 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 269 | unsigned long flags; | ||
| 270 | u8 val; | ||
| 271 | |||
| 272 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 273 | val = M48T59_READ(M48T59_FLAGS); | ||
| 274 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 275 | |||
| 276 | seq_printf(seq, "battery\t\t: %s\n", | ||
| 277 | (val & M48T59_FLAGS_BF) ? "low" : "normal"); | ||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 282 | * IRQ handler for the RTC | ||
| 283 | */ | ||
| 284 | static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id) | ||
| 285 | { | ||
| 286 | struct device *dev = (struct device *)dev_id; | ||
| 287 | struct platform_device *pdev = to_platform_device(dev); | ||
| 288 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 289 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 290 | u8 event; | ||
| 291 | |||
| 292 | spin_lock(&m48t59->lock); | ||
| 293 | event = M48T59_READ(M48T59_FLAGS); | ||
| 294 | spin_unlock(&m48t59->lock); | ||
| 295 | |||
| 296 | if (event & M48T59_FLAGS_AF) { | ||
| 297 | rtc_update_irq(m48t59->rtc, 1, (RTC_AF | RTC_IRQF)); | ||
| 298 | return IRQ_HANDLED; | ||
| 299 | } | ||
| 300 | |||
| 301 | return IRQ_NONE; | ||
| 302 | } | ||
| 303 | |||
| 304 | static const struct rtc_class_ops m48t59_rtc_ops = { | ||
| 305 | .ioctl = m48t59_rtc_ioctl, | ||
| 306 | .read_time = m48t59_rtc_read_time, | ||
| 307 | .set_time = m48t59_rtc_set_time, | ||
| 308 | .read_alarm = m48t59_rtc_readalarm, | ||
| 309 | .set_alarm = m48t59_rtc_setalarm, | ||
| 310 | .proc = m48t59_rtc_proc, | ||
| 311 | }; | ||
| 312 | |||
| 313 | static ssize_t m48t59_nvram_read(struct kobject *kobj, | ||
| 314 | struct bin_attribute *bin_attr, | ||
| 315 | char *buf, loff_t pos, size_t size) | ||
| 316 | { | ||
| 317 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 318 | struct platform_device *pdev = to_platform_device(dev); | ||
| 319 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 320 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 321 | ssize_t cnt = 0; | ||
| 322 | unsigned long flags; | ||
| 323 | |||
| 324 | for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { | ||
| 325 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 326 | *buf++ = M48T59_READ(cnt); | ||
| 327 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 328 | } | ||
| 329 | |||
| 330 | return cnt; | ||
| 331 | } | ||
| 332 | |||
| 333 | static ssize_t m48t59_nvram_write(struct kobject *kobj, | ||
| 334 | struct bin_attribute *bin_attr, | ||
| 335 | char *buf, loff_t pos, size_t size) | ||
| 336 | { | ||
| 337 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 338 | struct platform_device *pdev = to_platform_device(dev); | ||
| 339 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 340 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 341 | ssize_t cnt = 0; | ||
| 342 | unsigned long flags; | ||
| 343 | |||
| 344 | for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) { | ||
| 345 | spin_lock_irqsave(&m48t59->lock, flags); | ||
| 346 | M48T59_WRITE(*buf++, cnt); | ||
| 347 | spin_unlock_irqrestore(&m48t59->lock, flags); | ||
| 348 | } | ||
| 349 | |||
| 350 | return cnt; | ||
| 351 | } | ||
| 352 | |||
| 353 | static struct bin_attribute m48t59_nvram_attr = { | ||
| 354 | .attr = { | ||
| 355 | .name = "nvram", | ||
| 356 | .mode = S_IRUGO | S_IWUGO, | ||
| 357 | .owner = THIS_MODULE, | ||
| 358 | }, | ||
| 359 | .read = m48t59_nvram_read, | ||
| 360 | .write = m48t59_nvram_write, | ||
| 361 | }; | ||
| 362 | |||
| 363 | static int __devinit m48t59_rtc_probe(struct platform_device *pdev) | ||
| 364 | { | ||
| 365 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; | ||
| 366 | struct m48t59_private *m48t59 = NULL; | ||
| 367 | struct resource *res; | ||
| 368 | int ret = -ENOMEM; | ||
| 369 | |||
| 370 | /* This chip could be memory-mapped or I/O-mapped */ | ||
| 371 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 372 | if (!res) { | ||
| 373 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
| 374 | if (!res) | ||
| 375 | return -EINVAL; | ||
| 376 | } | ||
| 377 | |||
| 378 | if (res->flags & IORESOURCE_IO) { | ||
| 379 | /* If we are I/O-mapped, the platform should provide | ||
| 380 | * the operations accessing chip registers. | ||
| 381 | */ | ||
| 382 | if (!pdata || !pdata->write_byte || !pdata->read_byte) | ||
| 383 | return -EINVAL; | ||
| 384 | } else if (res->flags & IORESOURCE_MEM) { | ||
| 385 | /* we are memory-mapped */ | ||
| 386 | if (!pdata) { | ||
| 387 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
| 388 | if (!pdata) | ||
| 389 | return -ENOMEM; | ||
| 390 | /* Ensure we only kmalloc platform data once */ | ||
| 391 | pdev->dev.platform_data = pdata; | ||
| 392 | } | ||
| 393 | |||
| 394 | /* Try to use the generic memory read/write ops */ | ||
| 395 | if (!pdata->write_byte) | ||
| 396 | pdata->write_byte = m48t59_mem_writeb; | ||
| 397 | if (!pdata->read_byte) | ||
| 398 | pdata->read_byte = m48t59_mem_readb; | ||
| 399 | } | ||
| 400 | |||
| 401 | m48t59 = kzalloc(sizeof(*m48t59), GFP_KERNEL); | ||
| 402 | if (!m48t59) | ||
| 403 | return -ENOMEM; | ||
| 404 | |||
| 405 | m48t59->size = res->end - res->start + 1; | ||
| 406 | m48t59->ioaddr = ioremap(res->start, m48t59->size); | ||
| 407 | if (!m48t59->ioaddr) | ||
| 408 | goto out; | ||
| 409 | |||
| 410 | /* Try to get irq number. We also can work in | ||
| 411 | * the mode without IRQ. | ||
| 412 | */ | ||
| 413 | m48t59->irq = platform_get_irq(pdev, 0); | ||
| 414 | if (m48t59->irq < 0) | ||
| 415 | m48t59->irq = NO_IRQ; | ||
| 416 | |||
| 417 | if (m48t59->irq != NO_IRQ) { | ||
| 418 | ret = request_irq(m48t59->irq, m48t59_rtc_interrupt, | ||
| 419 | IRQF_SHARED, "rtc-m48t59", &pdev->dev); | ||
| 420 | if (ret) | ||
| 421 | goto out; | ||
| 422 | } | ||
| 423 | |||
| 424 | m48t59->rtc = rtc_device_register("m48t59", &pdev->dev, | ||
| 425 | &m48t59_rtc_ops, THIS_MODULE); | ||
| 426 | if (IS_ERR(m48t59->rtc)) { | ||
| 427 | ret = PTR_ERR(m48t59->rtc); | ||
| 428 | goto out; | ||
| 429 | } | ||
| 430 | |||
| 431 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); | ||
| 432 | if (ret) | ||
| 433 | goto out; | ||
| 434 | |||
| 435 | spin_lock_init(&m48t59->lock); | ||
| 436 | platform_set_drvdata(pdev, m48t59); | ||
| 437 | return 0; | ||
| 438 | |||
| 439 | out: | ||
| 440 | if (!IS_ERR(m48t59->rtc)) | ||
| 441 | rtc_device_unregister(m48t59->rtc); | ||
| 442 | if (m48t59->irq != NO_IRQ) | ||
| 443 | free_irq(m48t59->irq, &pdev->dev); | ||
| 444 | if (m48t59->ioaddr) | ||
| 445 | iounmap(m48t59->ioaddr); | ||
| 446 | if (m48t59) | ||
| 447 | kfree(m48t59); | ||
| 448 | return ret; | ||
| 449 | } | ||
| 450 | |||
| 451 | static int __devexit m48t59_rtc_remove(struct platform_device *pdev) | ||
| 452 | { | ||
| 453 | struct m48t59_private *m48t59 = platform_get_drvdata(pdev); | ||
| 454 | |||
| 455 | sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); | ||
| 456 | if (!IS_ERR(m48t59->rtc)) | ||
| 457 | rtc_device_unregister(m48t59->rtc); | ||
| 458 | if (m48t59->ioaddr) | ||
| 459 | iounmap(m48t59->ioaddr); | ||
| 460 | if (m48t59->irq != NO_IRQ) | ||
| 461 | free_irq(m48t59->irq, &pdev->dev); | ||
| 462 | platform_set_drvdata(pdev, NULL); | ||
| 463 | kfree(m48t59); | ||
| 464 | return 0; | ||
| 465 | } | ||
| 466 | |||
| 467 | static struct platform_driver m48t59_rtc_platdrv = { | ||
| 468 | .driver = { | ||
| 469 | .name = "rtc-m48t59", | ||
| 470 | .owner = THIS_MODULE, | ||
| 471 | }, | ||
| 472 | .probe = m48t59_rtc_probe, | ||
| 473 | .remove = __devexit_p(m48t59_rtc_remove), | ||
| 474 | }; | ||
| 475 | |||
| 476 | static int __init m48t59_rtc_init(void) | ||
| 477 | { | ||
| 478 | return platform_driver_register(&m48t59_rtc_platdrv); | ||
| 479 | } | ||
| 480 | |||
| 481 | static void __exit m48t59_rtc_exit(void) | ||
| 482 | { | ||
| 483 | platform_driver_unregister(&m48t59_rtc_platdrv); | ||
| 484 | } | ||
| 485 | |||
| 486 | module_init(m48t59_rtc_init); | ||
| 487 | module_exit(m48t59_rtc_exit); | ||
| 488 | |||
| 489 | MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>"); | ||
| 490 | MODULE_DESCRIPTION("M48T59 RTC driver"); | ||
| 491 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index eee4ee5bb75a..a1cd448639c9 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c | |||
| @@ -31,17 +31,24 @@ | |||
| 31 | #define MAX6900_REG_DW 5 /* day of week 1-7 */ | 31 | #define MAX6900_REG_DW 5 /* day of week 1-7 */ |
| 32 | #define MAX6900_REG_YR 6 /* year 00-99 */ | 32 | #define MAX6900_REG_YR 6 /* year 00-99 */ |
| 33 | #define MAX6900_REG_CT 7 /* control */ | 33 | #define MAX6900_REG_CT 7 /* control */ |
| 34 | #define MAX6900_REG_LEN 8 | 34 | /* register 8 is undocumented */ |
| 35 | #define MAX6900_REG_CENTURY 9 /* century */ | ||
| 36 | #define MAX6900_REG_LEN 10 | ||
| 37 | |||
| 38 | #define MAX6900_BURST_LEN 8 /* can burst r/w first 8 regs */ | ||
| 35 | 39 | ||
| 36 | #define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */ | 40 | #define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */ |
| 37 | 41 | ||
| 42 | |||
| 38 | /* | 43 | /* |
| 39 | * register read/write commands | 44 | * register read/write commands |
| 40 | */ | 45 | */ |
| 41 | #define MAX6900_REG_CONTROL_WRITE 0x8e | 46 | #define MAX6900_REG_CONTROL_WRITE 0x8e |
| 42 | #define MAX6900_REG_BURST_READ 0xbf | 47 | #define MAX6900_REG_CENTURY_WRITE 0x92 |
| 43 | #define MAX6900_REG_BURST_WRITE 0xbe | 48 | #define MAX6900_REG_CENTURY_READ 0x93 |
| 44 | #define MAX6900_REG_RESERVED_READ 0x96 | 49 | #define MAX6900_REG_RESERVED_READ 0x96 |
| 50 | #define MAX6900_REG_BURST_WRITE 0xbe | ||
| 51 | #define MAX6900_REG_BURST_READ 0xbf | ||
| 45 | 52 | ||
| 46 | #define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */ | 53 | #define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */ |
| 47 | 54 | ||
| @@ -58,19 +65,32 @@ static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind); | |||
| 58 | 65 | ||
| 59 | static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) | 66 | static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) |
| 60 | { | 67 | { |
| 61 | u8 reg_addr[1] = { MAX6900_REG_BURST_READ }; | 68 | u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ }; |
| 62 | struct i2c_msg msgs[2] = { | 69 | u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ }; |
| 70 | struct i2c_msg msgs[4] = { | ||
| 63 | { | 71 | { |
| 64 | .addr = client->addr, | 72 | .addr = client->addr, |
| 65 | .flags = 0, /* write */ | 73 | .flags = 0, /* write */ |
| 66 | .len = sizeof(reg_addr), | 74 | .len = sizeof(reg_burst_read), |
| 67 | .buf = reg_addr | 75 | .buf = reg_burst_read |
| 68 | }, | 76 | }, |
| 69 | { | 77 | { |
| 70 | .addr = client->addr, | 78 | .addr = client->addr, |
| 71 | .flags = I2C_M_RD, | 79 | .flags = I2C_M_RD, |
| 72 | .len = MAX6900_REG_LEN, | 80 | .len = MAX6900_BURST_LEN, |
| 73 | .buf = buf | 81 | .buf = buf |
| 82 | }, | ||
| 83 | { | ||
| 84 | .addr = client->addr, | ||
| 85 | .flags = 0, /* write */ | ||
| 86 | .len = sizeof(reg_century_read), | ||
| 87 | .buf = reg_century_read | ||
| 88 | }, | ||
| 89 | { | ||
| 90 | .addr = client->addr, | ||
| 91 | .flags = I2C_M_RD, | ||
| 92 | .len = sizeof(buf[MAX6900_REG_CENTURY]), | ||
| 93 | .buf = &buf[MAX6900_REG_CENTURY] | ||
| 74 | } | 94 | } |
| 75 | }; | 95 | }; |
| 76 | int rc; | 96 | int rc; |
| @@ -86,33 +106,58 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) | |||
| 86 | 106 | ||
| 87 | static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) | 107 | static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) |
| 88 | { | 108 | { |
| 89 | u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE }; | 109 | u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE }; |
| 90 | struct i2c_msg msgs[1] = { | 110 | struct i2c_msg century_msgs[1] = { |
| 91 | { | 111 | { |
| 92 | .addr = client->addr, | 112 | .addr = client->addr, |
| 93 | .flags = 0, /* write */ | 113 | .flags = 0, /* write */ |
| 94 | .len = MAX6900_REG_LEN + 1, | 114 | .len = sizeof(i2c_century_buf), |
| 95 | .buf = i2c_buf | 115 | .buf = i2c_century_buf |
| 116 | } | ||
| 117 | }; | ||
| 118 | u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE }; | ||
| 119 | struct i2c_msg burst_msgs[1] = { | ||
| 120 | { | ||
| 121 | .addr = client->addr, | ||
| 122 | .flags = 0, /* write */ | ||
| 123 | .len = sizeof(i2c_burst_buf), | ||
| 124 | .buf = i2c_burst_buf | ||
| 96 | } | 125 | } |
| 97 | }; | 126 | }; |
| 98 | int rc; | 127 | int rc; |
| 99 | 128 | ||
| 100 | memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN); | 129 | /* |
| 130 | * We have to make separate calls to i2c_transfer because of | ||
| 131 | * the need to delay after each write to the chip. Also, | ||
| 132 | * we write the century byte first, since we set the write-protect | ||
| 133 | * bit as part of the burst write. | ||
| 134 | */ | ||
| 135 | i2c_century_buf[1] = buf[MAX6900_REG_CENTURY]; | ||
| 136 | rc = i2c_transfer(client->adapter, century_msgs, | ||
| 137 | ARRAY_SIZE(century_msgs)); | ||
| 138 | if (rc != ARRAY_SIZE(century_msgs)) | ||
| 139 | goto write_failed; | ||
| 140 | msleep(MAX6900_IDLE_TIME_AFTER_WRITE); | ||
| 101 | 141 | ||
| 102 | rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | 142 | memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN); |
| 103 | if (rc != ARRAY_SIZE(msgs)) { | 143 | |
| 104 | dev_err(&client->dev, "%s: register write failed\n", | 144 | rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs)); |
| 105 | __FUNCTION__); | 145 | if (rc != ARRAY_SIZE(burst_msgs)) |
| 106 | return -EIO; | 146 | goto write_failed; |
| 107 | } | ||
| 108 | msleep(MAX6900_IDLE_TIME_AFTER_WRITE); | 147 | msleep(MAX6900_IDLE_TIME_AFTER_WRITE); |
| 148 | |||
| 109 | return 0; | 149 | return 0; |
| 150 | |||
| 151 | write_failed: | ||
| 152 | dev_err(&client->dev, "%s: register write failed\n", | ||
| 153 | __FUNCTION__); | ||
| 154 | return -EIO; | ||
| 110 | } | 155 | } |
| 111 | 156 | ||
| 112 | static int max6900_i2c_validate_client(struct i2c_client *client) | 157 | static int max6900_i2c_validate_client(struct i2c_client *client) |
| 113 | { | 158 | { |
| 114 | u8 regs[MAX6900_REG_LEN]; | 159 | u8 regs[MAX6900_REG_LEN]; |
| 115 | u8 zero_mask[MAX6900_REG_LEN] = { | 160 | u8 zero_mask[] = { |
| 116 | 0x80, /* seconds */ | 161 | 0x80, /* seconds */ |
| 117 | 0x80, /* minutes */ | 162 | 0x80, /* minutes */ |
| 118 | 0x40, /* hours */ | 163 | 0x40, /* hours */ |
| @@ -134,7 +179,7 @@ static int max6900_i2c_validate_client(struct i2c_client *client) | |||
| 134 | if (rc < 0) | 179 | if (rc < 0) |
| 135 | return rc; | 180 | return rc; |
| 136 | 181 | ||
| 137 | for (i = 0; i < MAX6900_REG_LEN; ++i) { | 182 | for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) { |
| 138 | if (regs[i] & zero_mask[i]) | 183 | if (regs[i] & zero_mask[i]) |
| 139 | return -ENODEV; | 184 | return -ENODEV; |
| 140 | } | 185 | } |
| @@ -156,7 +201,8 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) | |||
| 156 | tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f); | 201 | tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f); |
| 157 | tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]); | 202 | tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]); |
| 158 | tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1; | 203 | tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1; |
| 159 | tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100; | 204 | tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + |
| 205 | BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900; | ||
| 160 | tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]); | 206 | tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]); |
| 161 | 207 | ||
| 162 | return 0; | 208 | return 0; |
| @@ -189,9 +235,11 @@ static int max6900_i2c_set_time(struct i2c_client *client, | |||
| 189 | regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour); | 235 | regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour); |
| 190 | regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday); | 236 | regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday); |
| 191 | regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1); | 237 | regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1); |
| 192 | regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100); | ||
| 193 | regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday); | 238 | regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday); |
| 194 | regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; /* set write protect */ | 239 | regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100); |
| 240 | regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100); | ||
| 241 | /* set write protect */ | ||
| 242 | regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; | ||
| 195 | 243 | ||
| 196 | rc = max6900_i2c_write_regs(client, regs); | 244 | rc = max6900_i2c_write_regs(client, regs); |
| 197 | if (rc < 0) | 245 | if (rc < 0) |
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 09bbe575647b..6b67b5097927 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c | |||
| @@ -13,13 +13,7 @@ | |||
| 13 | #include <linux/rtc.h> | 13 | #include <linux/rtc.h> |
| 14 | #include <linux/bcd.h> | 14 | #include <linux/bcd.h> |
| 15 | 15 | ||
| 16 | #define DRV_VERSION "0.4" | 16 | #define DRV_VERSION "0.5" |
| 17 | |||
| 18 | /* Addresses to scan */ | ||
| 19 | static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; | ||
| 20 | |||
| 21 | /* Insmod parameters */ | ||
| 22 | I2C_CLIENT_INSMOD; | ||
| 23 | 17 | ||
| 24 | 18 | ||
| 25 | /* | 19 | /* |
| @@ -88,9 +82,6 @@ struct rs5c372 { | |||
| 88 | unsigned has_irq:1; | 82 | unsigned has_irq:1; |
| 89 | char buf[17]; | 83 | char buf[17]; |
| 90 | char *regs; | 84 | char *regs; |
| 91 | |||
| 92 | /* on conversion to a "new style" i2c driver, this vanishes */ | ||
| 93 | struct i2c_client dev; | ||
| 94 | }; | 85 | }; |
| 95 | 86 | ||
| 96 | static int rs5c_get_regs(struct rs5c372 *rs5c) | 87 | static int rs5c_get_regs(struct rs5c372 *rs5c) |
| @@ -483,25 +474,35 @@ static int rs5c_sysfs_register(struct device *dev) | |||
| 483 | return err; | 474 | return err; |
| 484 | } | 475 | } |
| 485 | 476 | ||
| 477 | static void rs5c_sysfs_unregister(struct device *dev) | ||
| 478 | { | ||
| 479 | device_remove_file(dev, &dev_attr_trim); | ||
| 480 | device_remove_file(dev, &dev_attr_osc); | ||
| 481 | } | ||
| 482 | |||
| 486 | #else | 483 | #else |
| 487 | static int rs5c_sysfs_register(struct device *dev) | 484 | static int rs5c_sysfs_register(struct device *dev) |
| 488 | { | 485 | { |
| 489 | return 0; | 486 | return 0; |
| 490 | } | 487 | } |
| 488 | |||
| 489 | static void rs5c_sysfs_unregister(struct device *dev) | ||
| 490 | { | ||
| 491 | /* nothing */ | ||
| 492 | } | ||
| 491 | #endif /* SYSFS */ | 493 | #endif /* SYSFS */ |
| 492 | 494 | ||
| 493 | static struct i2c_driver rs5c372_driver; | 495 | static struct i2c_driver rs5c372_driver; |
| 494 | 496 | ||
| 495 | static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | 497 | static int rs5c372_probe(struct i2c_client *client) |
| 496 | { | 498 | { |
| 497 | int err = 0; | 499 | int err = 0; |
| 498 | struct i2c_client *client; | ||
| 499 | struct rs5c372 *rs5c372; | 500 | struct rs5c372 *rs5c372; |
| 500 | struct rtc_time tm; | 501 | struct rtc_time tm; |
| 501 | 502 | ||
| 502 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | 503 | dev_dbg(&client->dev, "%s\n", __FUNCTION__); |
| 503 | 504 | ||
| 504 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { | 505 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { |
| 505 | err = -ENODEV; | 506 | err = -ENODEV; |
| 506 | goto exit; | 507 | goto exit; |
| 507 | } | 508 | } |
| @@ -514,35 +515,22 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
| 514 | /* we read registers 0x0f then 0x00-0x0f; skip the first one */ | 515 | /* we read registers 0x0f then 0x00-0x0f; skip the first one */ |
| 515 | rs5c372->regs=&rs5c372->buf[1]; | 516 | rs5c372->regs=&rs5c372->buf[1]; |
| 516 | 517 | ||
| 517 | /* On conversion to a "new style" i2c driver, we'll be handed | ||
| 518 | * the i2c_client (we won't create it) | ||
| 519 | */ | ||
| 520 | client = &rs5c372->dev; | ||
| 521 | rs5c372->client = client; | 518 | rs5c372->client = client; |
| 522 | |||
| 523 | /* I2C client */ | ||
| 524 | client->addr = address; | ||
| 525 | client->driver = &rs5c372_driver; | ||
| 526 | client->adapter = adapter; | ||
| 527 | |||
| 528 | strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE); | ||
| 529 | |||
| 530 | i2c_set_clientdata(client, rs5c372); | 519 | i2c_set_clientdata(client, rs5c372); |
| 531 | 520 | ||
| 532 | /* Inform the i2c layer */ | ||
| 533 | if ((err = i2c_attach_client(client))) | ||
| 534 | goto exit_kfree; | ||
| 535 | |||
| 536 | err = rs5c_get_regs(rs5c372); | 521 | err = rs5c_get_regs(rs5c372); |
| 537 | if (err < 0) | 522 | if (err < 0) |
| 538 | goto exit_detach; | 523 | goto exit_kfree; |
| 539 | 524 | ||
| 540 | /* For "new style" drivers, irq is in i2c_client and chip type | 525 | if (strcmp(client->name, "rs5c372a") == 0) |
| 541 | * info comes from i2c_client.dev.platform_data. Meanwhile: | 526 | rs5c372->type = rtc_rs5c372a; |
| 542 | * | 527 | else if (strcmp(client->name, "rs5c372b") == 0) |
| 543 | * STICK BOARD-SPECIFIC SETUP CODE RIGHT HERE | 528 | rs5c372->type = rtc_rs5c372b; |
| 544 | */ | 529 | else if (strcmp(client->name, "rv5c386") == 0) |
| 545 | if (rs5c372->type == rtc_undef) { | 530 | rs5c372->type = rtc_rv5c386; |
| 531 | else if (strcmp(client->name, "rv5c387a") == 0) | ||
| 532 | rs5c372->type = rtc_rv5c387a; | ||
| 533 | else { | ||
| 546 | rs5c372->type = rtc_rs5c372b; | 534 | rs5c372->type = rtc_rs5c372b; |
| 547 | dev_warn(&client->dev, "assuming rs5c372b\n"); | 535 | dev_warn(&client->dev, "assuming rs5c372b\n"); |
| 548 | } | 536 | } |
| @@ -567,7 +555,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
| 567 | break; | 555 | break; |
| 568 | default: | 556 | default: |
| 569 | dev_err(&client->dev, "unknown RTC type\n"); | 557 | dev_err(&client->dev, "unknown RTC type\n"); |
| 570 | goto exit_detach; | 558 | goto exit_kfree; |
| 571 | } | 559 | } |
| 572 | 560 | ||
| 573 | /* if the oscillator lost power and no other software (like | 561 | /* if the oscillator lost power and no other software (like |
| @@ -601,7 +589,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
| 601 | 589 | ||
| 602 | if ((i2c_master_send(client, buf, 3)) != 3) { | 590 | if ((i2c_master_send(client, buf, 3)) != 3) { |
| 603 | dev_err(&client->dev, "setup error\n"); | 591 | dev_err(&client->dev, "setup error\n"); |
| 604 | goto exit_detach; | 592 | goto exit_kfree; |
| 605 | } | 593 | } |
| 606 | rs5c372->regs[RS5C_REG_CTRL1] = buf[1]; | 594 | rs5c372->regs[RS5C_REG_CTRL1] = buf[1]; |
| 607 | rs5c372->regs[RS5C_REG_CTRL2] = buf[2]; | 595 | rs5c372->regs[RS5C_REG_CTRL2] = buf[2]; |
| @@ -621,14 +609,14 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
| 621 | rs5c372->time24 ? "24hr" : "am/pm" | 609 | rs5c372->time24 ? "24hr" : "am/pm" |
| 622 | ); | 610 | ); |
| 623 | 611 | ||
| 624 | /* FIXME when client->irq exists, use it to register alarm irq */ | 612 | /* REVISIT use client->irq to register alarm irq ... */ |
| 625 | 613 | ||
| 626 | rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name, | 614 | rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name, |
| 627 | &client->dev, &rs5c372_rtc_ops, THIS_MODULE); | 615 | &client->dev, &rs5c372_rtc_ops, THIS_MODULE); |
| 628 | 616 | ||
| 629 | if (IS_ERR(rs5c372->rtc)) { | 617 | if (IS_ERR(rs5c372->rtc)) { |
| 630 | err = PTR_ERR(rs5c372->rtc); | 618 | err = PTR_ERR(rs5c372->rtc); |
| 631 | goto exit_detach; | 619 | goto exit_kfree; |
| 632 | } | 620 | } |
| 633 | 621 | ||
| 634 | err = rs5c_sysfs_register(&client->dev); | 622 | err = rs5c_sysfs_register(&client->dev); |
| @@ -640,9 +628,6 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | |||
| 640 | exit_devreg: | 628 | exit_devreg: |
| 641 | rtc_device_unregister(rs5c372->rtc); | 629 | rtc_device_unregister(rs5c372->rtc); |
| 642 | 630 | ||
| 643 | exit_detach: | ||
| 644 | i2c_detach_client(client); | ||
| 645 | |||
| 646 | exit_kfree: | 631 | exit_kfree: |
| 647 | kfree(rs5c372); | 632 | kfree(rs5c372); |
| 648 | 633 | ||
| @@ -650,24 +635,12 @@ exit: | |||
| 650 | return err; | 635 | return err; |
| 651 | } | 636 | } |
| 652 | 637 | ||
| 653 | static int rs5c372_attach(struct i2c_adapter *adapter) | 638 | static int rs5c372_remove(struct i2c_client *client) |
| 654 | { | 639 | { |
| 655 | return i2c_probe(adapter, &addr_data, rs5c372_probe); | ||
| 656 | } | ||
| 657 | |||
| 658 | static int rs5c372_detach(struct i2c_client *client) | ||
| 659 | { | ||
| 660 | int err; | ||
| 661 | struct rs5c372 *rs5c372 = i2c_get_clientdata(client); | 640 | struct rs5c372 *rs5c372 = i2c_get_clientdata(client); |
| 662 | 641 | ||
| 663 | if (rs5c372->rtc) | 642 | rtc_device_unregister(rs5c372->rtc); |
| 664 | rtc_device_unregister(rs5c372->rtc); | 643 | rs5c_sysfs_unregister(&client->dev); |
| 665 | |||
| 666 | /* REVISIT properly destroy the sysfs files ... */ | ||
| 667 | |||
| 668 | if ((err = i2c_detach_client(client))) | ||
| 669 | return err; | ||
| 670 | |||
| 671 | kfree(rs5c372); | 644 | kfree(rs5c372); |
| 672 | return 0; | 645 | return 0; |
| 673 | } | 646 | } |
| @@ -676,8 +649,8 @@ static struct i2c_driver rs5c372_driver = { | |||
| 676 | .driver = { | 649 | .driver = { |
| 677 | .name = "rtc-rs5c372", | 650 | .name = "rtc-rs5c372", |
| 678 | }, | 651 | }, |
| 679 | .attach_adapter = &rs5c372_attach, | 652 | .probe = rs5c372_probe, |
| 680 | .detach_client = &rs5c372_detach, | 653 | .remove = rs5c372_remove, |
| 681 | }; | 654 | }; |
| 682 | 655 | ||
| 683 | static __init int rs5c372_init(void) | 656 | static __init int rs5c372_init(void) |
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c new file mode 100644 index 000000000000..f10d3facecbe --- /dev/null +++ b/drivers/rtc/rtc-stk17ta8.c | |||
| @@ -0,0 +1,420 @@ | |||
| 1 | /* | ||
| 2 | * A RTC driver for the Simtek STK17TA8 | ||
| 3 | * | ||
| 4 | * By Thomas Hommel <thomas.hommel@gefanuc.com> | ||
| 5 | * | ||
| 6 | * Based on the DS1553 driver from | ||
| 7 | * Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/bcd.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/jiffies.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/rtc.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | |||
| 24 | #define DRV_VERSION "0.1" | ||
| 25 | |||
| 26 | #define RTC_REG_SIZE 0x20000 | ||
| 27 | #define RTC_OFFSET 0x1fff0 | ||
| 28 | |||
| 29 | #define RTC_FLAGS (RTC_OFFSET + 0) | ||
| 30 | #define RTC_CENTURY (RTC_OFFSET + 1) | ||
| 31 | #define RTC_SECONDS_ALARM (RTC_OFFSET + 2) | ||
| 32 | #define RTC_MINUTES_ALARM (RTC_OFFSET + 3) | ||
| 33 | #define RTC_HOURS_ALARM (RTC_OFFSET + 4) | ||
| 34 | #define RTC_DATE_ALARM (RTC_OFFSET + 5) | ||
| 35 | #define RTC_INTERRUPTS (RTC_OFFSET + 6) | ||
| 36 | #define RTC_WATCHDOG (RTC_OFFSET + 7) | ||
| 37 | #define RTC_CALIBRATION (RTC_OFFSET + 8) | ||
| 38 | #define RTC_SECONDS (RTC_OFFSET + 9) | ||
| 39 | #define RTC_MINUTES (RTC_OFFSET + 10) | ||
| 40 | #define RTC_HOURS (RTC_OFFSET + 11) | ||
| 41 | #define RTC_DAY (RTC_OFFSET + 12) | ||
| 42 | #define RTC_DATE (RTC_OFFSET + 13) | ||
| 43 | #define RTC_MONTH (RTC_OFFSET + 14) | ||
| 44 | #define RTC_YEAR (RTC_OFFSET + 15) | ||
| 45 | |||
| 46 | #define RTC_SECONDS_MASK 0x7f | ||
| 47 | #define RTC_DAY_MASK 0x07 | ||
| 48 | #define RTC_CAL_MASK 0x3f | ||
| 49 | |||
| 50 | /* Bits in the Calibration register */ | ||
| 51 | #define RTC_STOP 0x80 | ||
| 52 | |||
| 53 | /* Bits in the Flags register */ | ||
| 54 | #define RTC_FLAGS_AF 0x40 | ||
| 55 | #define RTC_FLAGS_PF 0x20 | ||
| 56 | #define RTC_WRITE 0x02 | ||
| 57 | #define RTC_READ 0x01 | ||
| 58 | |||
| 59 | /* Bits in the Interrupts register */ | ||
| 60 | #define RTC_INTS_AIE 0x40 | ||
| 61 | |||
| 62 | struct rtc_plat_data { | ||
| 63 | struct rtc_device *rtc; | ||
| 64 | void __iomem *ioaddr; | ||
| 65 | unsigned long baseaddr; | ||
| 66 | unsigned long last_jiffies; | ||
| 67 | int irq; | ||
| 68 | unsigned int irqen; | ||
| 69 | int alrm_sec; | ||
| 70 | int alrm_min; | ||
| 71 | int alrm_hour; | ||
| 72 | int alrm_mday; | ||
| 73 | }; | ||
| 74 | |||
| 75 | static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 76 | { | ||
| 77 | struct platform_device *pdev = to_platform_device(dev); | ||
| 78 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 79 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 80 | u8 flags; | ||
| 81 | |||
| 82 | flags = readb(pdata->ioaddr + RTC_FLAGS); | ||
| 83 | writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS); | ||
| 84 | |||
| 85 | writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR); | ||
| 86 | writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH); | ||
| 87 | writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY); | ||
| 88 | writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE); | ||
| 89 | writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS); | ||
| 90 | writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES); | ||
| 91 | writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS); | ||
| 92 | writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY); | ||
| 93 | |||
| 94 | writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS); | ||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 99 | { | ||
| 100 | struct platform_device *pdev = to_platform_device(dev); | ||
| 101 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 102 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 103 | unsigned int year, month, day, hour, minute, second, week; | ||
| 104 | unsigned int century; | ||
| 105 | u8 flags; | ||
| 106 | |||
| 107 | /* give enough time to update RTC in case of continuous read */ | ||
| 108 | if (pdata->last_jiffies == jiffies) | ||
| 109 | msleep(1); | ||
| 110 | pdata->last_jiffies = jiffies; | ||
| 111 | |||
| 112 | flags = readb(pdata->ioaddr + RTC_FLAGS); | ||
| 113 | writeb(flags | RTC_READ, ioaddr + RTC_FLAGS); | ||
| 114 | second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK; | ||
| 115 | minute = readb(ioaddr + RTC_MINUTES); | ||
| 116 | hour = readb(ioaddr + RTC_HOURS); | ||
| 117 | day = readb(ioaddr + RTC_DATE); | ||
| 118 | week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK; | ||
| 119 | month = readb(ioaddr + RTC_MONTH); | ||
| 120 | year = readb(ioaddr + RTC_YEAR); | ||
| 121 | century = readb(ioaddr + RTC_CENTURY); | ||
| 122 | writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS); | ||
| 123 | tm->tm_sec = BCD2BIN(second); | ||
| 124 | tm->tm_min = BCD2BIN(minute); | ||
| 125 | tm->tm_hour = BCD2BIN(hour); | ||
| 126 | tm->tm_mday = BCD2BIN(day); | ||
| 127 | tm->tm_wday = BCD2BIN(week); | ||
| 128 | tm->tm_mon = BCD2BIN(month) - 1; | ||
| 129 | /* year is 1900 + tm->tm_year */ | ||
| 130 | tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900; | ||
| 131 | |||
| 132 | if (rtc_valid_tm(tm) < 0) { | ||
| 133 | dev_err(dev, "retrieved date/time is not valid.\n"); | ||
| 134 | rtc_time_to_tm(0, tm); | ||
| 135 | } | ||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) | ||
| 140 | { | ||
| 141 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 142 | unsigned long irqflags; | ||
| 143 | u8 flags; | ||
| 144 | |||
| 145 | spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); | ||
| 146 | |||
| 147 | flags = readb(ioaddr + RTC_FLAGS); | ||
| 148 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); | ||
| 149 | |||
| 150 | writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? | ||
| 151 | 0x80 : BIN2BCD(pdata->alrm_mday), | ||
| 152 | ioaddr + RTC_DATE_ALARM); | ||
| 153 | writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ? | ||
| 154 | 0x80 : BIN2BCD(pdata->alrm_hour), | ||
| 155 | ioaddr + RTC_HOURS_ALARM); | ||
| 156 | writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ? | ||
| 157 | 0x80 : BIN2BCD(pdata->alrm_min), | ||
| 158 | ioaddr + RTC_MINUTES_ALARM); | ||
| 159 | writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ? | ||
| 160 | 0x80 : BIN2BCD(pdata->alrm_sec), | ||
| 161 | ioaddr + RTC_SECONDS_ALARM); | ||
| 162 | writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); | ||
| 163 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ | ||
| 164 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); | ||
| 165 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); | ||
| 166 | } | ||
| 167 | |||
| 168 | static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 169 | { | ||
| 170 | struct platform_device *pdev = to_platform_device(dev); | ||
| 171 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 172 | |||
| 173 | if (pdata->irq < 0) | ||
| 174 | return -EINVAL; | ||
| 175 | pdata->alrm_mday = alrm->time.tm_mday; | ||
| 176 | pdata->alrm_hour = alrm->time.tm_hour; | ||
| 177 | pdata->alrm_min = alrm->time.tm_min; | ||
| 178 | pdata->alrm_sec = alrm->time.tm_sec; | ||
| 179 | if (alrm->enabled) | ||
| 180 | pdata->irqen |= RTC_AF; | ||
| 181 | stk17ta8_rtc_update_alarm(pdata); | ||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
| 186 | { | ||
| 187 | struct platform_device *pdev = to_platform_device(dev); | ||
| 188 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 189 | |||
| 190 | if (pdata->irq < 0) | ||
| 191 | return -EINVAL; | ||
| 192 | alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; | ||
| 193 | alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; | ||
| 194 | alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min; | ||
| 195 | alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec; | ||
| 196 | alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0; | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id) | ||
| 201 | { | ||
| 202 | struct platform_device *pdev = dev_id; | ||
| 203 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 204 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 205 | unsigned long events = RTC_IRQF; | ||
| 206 | |||
| 207 | /* read and clear interrupt */ | ||
| 208 | if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) | ||
| 209 | return IRQ_NONE; | ||
| 210 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) | ||
| 211 | events |= RTC_UF; | ||
| 212 | else | ||
| 213 | events |= RTC_AF; | ||
| 214 | rtc_update_irq(pdata->rtc, 1, events); | ||
| 215 | return IRQ_HANDLED; | ||
| 216 | } | ||
| 217 | |||
| 218 | static void stk17ta8_rtc_release(struct device *dev) | ||
| 219 | { | ||
| 220 | struct platform_device *pdev = to_platform_device(dev); | ||
| 221 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 222 | |||
| 223 | if (pdata->irq >= 0) { | ||
| 224 | pdata->irqen = 0; | ||
| 225 | stk17ta8_rtc_update_alarm(pdata); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
| 230 | unsigned long arg) | ||
| 231 | { | ||
| 232 | struct platform_device *pdev = to_platform_device(dev); | ||
| 233 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 234 | |||
| 235 | if (pdata->irq < 0) | ||
| 236 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | ||
| 237 | switch (cmd) { | ||
| 238 | case RTC_AIE_OFF: | ||
| 239 | pdata->irqen &= ~RTC_AF; | ||
| 240 | stk17ta8_rtc_update_alarm(pdata); | ||
| 241 | break; | ||
| 242 | case RTC_AIE_ON: | ||
| 243 | pdata->irqen |= RTC_AF; | ||
| 244 | stk17ta8_rtc_update_alarm(pdata); | ||
| 245 | break; | ||
| 246 | default: | ||
| 247 | return -ENOIOCTLCMD; | ||
| 248 | } | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static const struct rtc_class_ops stk17ta8_rtc_ops = { | ||
| 253 | .read_time = stk17ta8_rtc_read_time, | ||
| 254 | .set_time = stk17ta8_rtc_set_time, | ||
| 255 | .read_alarm = stk17ta8_rtc_read_alarm, | ||
| 256 | .set_alarm = stk17ta8_rtc_set_alarm, | ||
| 257 | .release = stk17ta8_rtc_release, | ||
| 258 | .ioctl = stk17ta8_rtc_ioctl, | ||
| 259 | }; | ||
| 260 | |||
| 261 | static ssize_t stk17ta8_nvram_read(struct kobject *kobj, char *buf, | ||
| 262 | loff_t pos, size_t size) | ||
| 263 | { | ||
| 264 | struct platform_device *pdev = | ||
| 265 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
| 266 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 267 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 268 | ssize_t count; | ||
| 269 | |||
| 270 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
| 271 | *buf++ = readb(ioaddr + pos++); | ||
| 272 | return count; | ||
| 273 | } | ||
| 274 | |||
| 275 | static ssize_t stk17ta8_nvram_write(struct kobject *kobj, char *buf, | ||
| 276 | loff_t pos, size_t size) | ||
| 277 | { | ||
| 278 | struct platform_device *pdev = | ||
| 279 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
| 280 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 281 | void __iomem *ioaddr = pdata->ioaddr; | ||
| 282 | ssize_t count; | ||
| 283 | |||
| 284 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
| 285 | writeb(*buf++, ioaddr + pos++); | ||
| 286 | return count; | ||
| 287 | } | ||
| 288 | |||
| 289 | static struct bin_attribute stk17ta8_nvram_attr = { | ||
| 290 | .attr = { | ||
| 291 | .name = "nvram", | ||
| 292 | .mode = S_IRUGO | S_IWUGO, | ||
| 293 | .owner = THIS_MODULE, | ||
| 294 | }, | ||
| 295 | .size = RTC_OFFSET, | ||
| 296 | .read = stk17ta8_nvram_read, | ||
| 297 | .write = stk17ta8_nvram_write, | ||
| 298 | }; | ||
| 299 | |||
| 300 | static int __init stk17ta8_rtc_probe(struct platform_device *pdev) | ||
| 301 | { | ||
| 302 | struct rtc_device *rtc; | ||
| 303 | struct resource *res; | ||
| 304 | unsigned int cal; | ||
| 305 | unsigned int flags; | ||
| 306 | struct rtc_plat_data *pdata; | ||
| 307 | void __iomem *ioaddr = NULL; | ||
| 308 | int ret = 0; | ||
| 309 | |||
| 310 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 311 | if (!res) | ||
| 312 | return -ENODEV; | ||
| 313 | |||
| 314 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
| 315 | if (!pdata) | ||
| 316 | return -ENOMEM; | ||
| 317 | pdata->irq = -1; | ||
| 318 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | ||
| 319 | ret = -EBUSY; | ||
| 320 | goto out; | ||
| 321 | } | ||
| 322 | pdata->baseaddr = res->start; | ||
| 323 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | ||
| 324 | if (!ioaddr) { | ||
| 325 | ret = -ENOMEM; | ||
| 326 | goto out; | ||
| 327 | } | ||
| 328 | pdata->ioaddr = ioaddr; | ||
| 329 | pdata->irq = platform_get_irq(pdev, 0); | ||
| 330 | |||
| 331 | /* turn RTC on if it was not on */ | ||
| 332 | cal = readb(ioaddr + RTC_CALIBRATION); | ||
| 333 | if (cal & RTC_STOP) { | ||
| 334 | cal &= RTC_CAL_MASK; | ||
| 335 | flags = readb(ioaddr + RTC_FLAGS); | ||
| 336 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); | ||
| 337 | writeb(cal, ioaddr + RTC_CALIBRATION); | ||
| 338 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); | ||
| 339 | } | ||
| 340 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) | ||
| 341 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | ||
| 342 | |||
| 343 | if (pdata->irq >= 0) { | ||
| 344 | writeb(0, ioaddr + RTC_INTERRUPTS); | ||
| 345 | if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, | ||
| 346 | IRQF_DISABLED | IRQF_SHARED, | ||
| 347 | pdev->name, pdev) < 0) { | ||
| 348 | dev_warn(&pdev->dev, "interrupt not available.\n"); | ||
| 349 | pdata->irq = -1; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
| 354 | &stk17ta8_rtc_ops, THIS_MODULE); | ||
| 355 | if (IS_ERR(rtc)) { | ||
| 356 | ret = PTR_ERR(rtc); | ||
| 357 | goto out; | ||
| 358 | } | ||
| 359 | pdata->rtc = rtc; | ||
| 360 | pdata->last_jiffies = jiffies; | ||
| 361 | platform_set_drvdata(pdev, pdata); | ||
| 362 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | ||
| 363 | if (ret) | ||
| 364 | goto out; | ||
| 365 | return 0; | ||
| 366 | out: | ||
| 367 | if (pdata->rtc) | ||
| 368 | rtc_device_unregister(pdata->rtc); | ||
| 369 | if (pdata->irq >= 0) | ||
| 370 | free_irq(pdata->irq, pdev); | ||
| 371 | if (ioaddr) | ||
| 372 | iounmap(ioaddr); | ||
| 373 | if (pdata->baseaddr) | ||
| 374 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
| 375 | kfree(pdata); | ||
| 376 | return ret; | ||
| 377 | } | ||
| 378 | |||
| 379 | static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) | ||
| 380 | { | ||
| 381 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
| 382 | |||
| 383 | sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | ||
| 384 | rtc_device_unregister(pdata->rtc); | ||
| 385 | if (pdata->irq >= 0) { | ||
| 386 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); | ||
| 387 | free_irq(pdata->irq, pdev); | ||
| 388 | } | ||
| 389 | iounmap(pdata->ioaddr); | ||
| 390 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
| 391 | kfree(pdata); | ||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | |||
| 395 | static struct platform_driver stk17ta8_rtc_driver = { | ||
| 396 | .probe = stk17ta8_rtc_probe, | ||
| 397 | .remove = __devexit_p(stk17ta8_rtc_remove), | ||
| 398 | .driver = { | ||
| 399 | .name = "stk17ta8", | ||
| 400 | .owner = THIS_MODULE, | ||
| 401 | }, | ||
| 402 | }; | ||
| 403 | |||
| 404 | static __init int stk17ta8_init(void) | ||
| 405 | { | ||
| 406 | return platform_driver_register(&stk17ta8_rtc_driver); | ||
| 407 | } | ||
| 408 | |||
| 409 | static __exit void stk17ta8_exit(void) | ||
| 410 | { | ||
| 411 | return platform_driver_unregister(&stk17ta8_rtc_driver); | ||
| 412 | } | ||
| 413 | |||
| 414 | module_init(stk17ta8_init); | ||
| 415 | module_exit(stk17ta8_exit); | ||
| 416 | |||
| 417 | MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>"); | ||
| 418 | MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver"); | ||
| 419 | MODULE_LICENSE("GPL"); | ||
| 420 | MODULE_VERSION(DRV_VERSION); | ||
