^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * I2C client/driver for the ST M41T80 family of i2c rtc chips.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Alexander Bigga <ab@mycable.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * 2006 (c) mycable GmbH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/bcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/rtc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #ifdef CONFIG_RTC_DRV_M41T80_WDT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define M41T80_REG_SSEC 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define M41T80_REG_SEC 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define M41T80_REG_MIN 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define M41T80_REG_HOUR 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define M41T80_REG_WDAY 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define M41T80_REG_DAY 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define M41T80_REG_MON 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define M41T80_REG_YEAR 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define M41T80_REG_ALARM_MON 0x0a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define M41T80_REG_ALARM_DAY 0x0b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define M41T80_REG_ALARM_HOUR 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define M41T80_REG_ALARM_MIN 0x0d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define M41T80_REG_ALARM_SEC 0x0e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define M41T80_REG_FLAGS 0x0f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define M41T80_REG_SQW 0x13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define M41T80_DATETIME_REG_SIZE (M41T80_REG_YEAR + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define M41T80_ALARM_REG_SIZE \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) (M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define M41T80_SQW_MAX_FREQ 32768
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define M41T80_SEC_ST BIT(7) /* ST: Stop Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define M41T80_ALMON_AFE BIT(7) /* AFE: AF Enable Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define M41T80_ALMON_SQWE BIT(6) /* SQWE: SQW Enable Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define M41T80_ALHOUR_HT BIT(6) /* HT: Halt Update Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define M41T80_FLAGS_OF BIT(2) /* OF: Oscillator Failure Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define M41T80_FLAGS_AF BIT(6) /* AF: Alarm Flag Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define M41T80_FLAGS_BATT_LOW BIT(4) /* BL: Battery Low Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define M41T80_WATCHDOG_RB2 BIT(7) /* RB: Watchdog resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define M41T80_WATCHDOG_RB1 BIT(1) /* RB: Watchdog resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define M41T80_WATCHDOG_RB0 BIT(0) /* RB: Watchdog resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define M41T80_FEATURE_HT BIT(0) /* Halt feature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define M41T80_FEATURE_BL BIT(1) /* Battery low indicator */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define M41T80_FEATURE_SQ BIT(2) /* Squarewave feature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define M41T80_FEATURE_WD BIT(3) /* Extra watchdog resolution */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define M41T80_FEATURE_SQ_ALT BIT(4) /* RSx bits are in reg 4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static const struct i2c_device_id m41t80_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) { "m41t80", M41T80_FEATURE_SQ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) { "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) MODULE_DEVICE_TABLE(i2c, m41t80_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static const struct of_device_id m41t80_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .compatible = "st,m41t62",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .compatible = "st,m41t65",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_WD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .compatible = "st,m41t80",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .data = (void *)(M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .compatible = "st,m41t81",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .compatible = "st,m41t81s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .compatible = "st,m41t82",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .compatible = "st,m41t83",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .compatible = "st,m41t84",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .compatible = "st,m41t85",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .compatible = "st,m41t87",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .compatible = "microcrystal,rv4162",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /* DT compatibility only, do not use compatibles below: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .compatible = "st,rv4162",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .compatible = "rv4162",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) MODULE_DEVICE_TABLE(of, m41t80_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct m41t80_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) unsigned long features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) struct rtc_device *rtc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #ifdef CONFIG_COMMON_CLK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct clk_hw sqw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) unsigned long freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) unsigned int sqwe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct i2c_client *client = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct m41t80_data *m41t80 = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct mutex *lock = &m41t80->rtc->ops_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) unsigned long events = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) int flags, flags_afe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) mutex_lock(lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) flags_afe = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (flags_afe < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) mutex_unlock(lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (flags <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) mutex_unlock(lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (flags & M41T80_FLAGS_AF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) flags &= ~M41T80_FLAGS_AF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) flags_afe &= ~M41T80_ALMON_AFE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) events |= RTC_AF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (events) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) rtc_update_irq(m41t80->rtc, 1, events);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) flags_afe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) mutex_unlock(lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) unsigned char buf[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) int err, flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (flags < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (flags & M41T80_FLAGS_OF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) dev_err(&client->dev, "Oscillator failure, data is invalid.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) err = i2c_smbus_read_i2c_block_data(client, M41T80_REG_SSEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) sizeof(buf), buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) dev_err(&client->dev, "Unable to read date\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) tm->tm_sec = bcd2bin(buf[M41T80_REG_SEC] & 0x7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) tm->tm_min = bcd2bin(buf[M41T80_REG_MIN] & 0x7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) tm->tm_hour = bcd2bin(buf[M41T80_REG_HOUR] & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) tm->tm_mday = bcd2bin(buf[M41T80_REG_DAY] & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) tm->tm_wday = buf[M41T80_REG_WDAY] & 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) tm->tm_mon = bcd2bin(buf[M41T80_REG_MON] & 0x1f) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* assume 20YY not 19YY, and ignore the Century Bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) tm->tm_year = bcd2bin(buf[M41T80_REG_YEAR]) + 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct m41t80_data *clientdata = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) unsigned char buf[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) int err, flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) buf[M41T80_REG_SSEC] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) buf[M41T80_REG_HOUR] = bin2bcd(tm->tm_hour);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) buf[M41T80_REG_DAY] = bin2bcd(tm->tm_mday);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) buf[M41T80_REG_WDAY] = tm->tm_wday;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* If the square wave output is controlled in the weekday register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (val < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) buf[M41T80_REG_WDAY] |= (val & 0xf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) sizeof(buf), buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) dev_err(&client->dev, "Unable to write to date registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) /* Clear the OF bit of Flags Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (flags < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) flags & ~M41T80_FLAGS_OF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) dev_err(&client->dev, "Unable to write flags register\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) struct m41t80_data *clientdata = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (clientdata->features & M41T80_FEATURE_BL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (reg < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) seq_printf(seq, "battery\t\t: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int flags, retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) flags = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (flags < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) flags |= M41T80_ALMON_AFE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) flags &= ~M41T80_ALMON_AFE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) dev_err(dev, "Unable to enable alarm IRQ %d\n", retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) u8 alarmvals[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int ret, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) alarmvals[0] = bin2bcd(alrm->time.tm_mon + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) alarmvals[1] = bin2bcd(alrm->time.tm_mday);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) alarmvals[2] = bin2bcd(alrm->time.tm_hour);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) alarmvals[3] = bin2bcd(alrm->time.tm_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) alarmvals[4] = bin2bcd(alrm->time.tm_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) /* Clear AF and AFE flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) ret & ~(M41T80_ALMON_AFE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) dev_err(dev, "Unable to clear AFE bit\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /* Keep SQWE bit value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) alarmvals[0] |= (ret & M41T80_ALMON_SQWE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) ret = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) ret & ~(M41T80_FLAGS_AF));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) dev_err(dev, "Unable to clear AF bit\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) /* Write the alarm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_ALARM_MON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 5, alarmvals);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* Enable the alarm interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (alrm->enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) alarmvals[0] |= M41T80_ALMON_AFE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) alarmvals[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) u8 alarmvals[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) int flags, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) ret = i2c_smbus_read_i2c_block_data(client, M41T80_REG_ALARM_MON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 5, alarmvals);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (ret != 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return ret < 0 ? ret : -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (flags < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) alrm->time.tm_sec = bcd2bin(alarmvals[4] & 0x7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) alrm->time.tm_min = bcd2bin(alarmvals[3] & 0x7f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static struct rtc_class_ops m41t80_rtc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) .read_time = m41t80_rtc_read_time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) .set_time = m41t80_rtc_set_time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) .proc = m41t80_rtc_proc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static int m41t80_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (client->irq >= 0 && device_may_wakeup(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) enable_irq_wake(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static int m41t80_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (client->irq >= 0 && device_may_wakeup(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) disable_irq_wake(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) #ifdef CONFIG_COMMON_CLK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) #define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static unsigned long m41t80_decode_freq(int setting)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return (setting == 0) ? 0 : (setting == 1) ? M41T80_SQW_MAX_FREQ :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) M41T80_SQW_MAX_FREQ >> setting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static unsigned long m41t80_get_freq(struct m41t80_data *m41t80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) struct i2c_client *client = m41t80->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) M41T80_REG_WDAY : M41T80_REG_SQW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) int ret = i2c_smbus_read_byte_data(client, reg_sqw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) return m41t80_decode_freq(ret >> 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return sqw_to_m41t80_data(hw)->freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) unsigned long *prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (rate >= M41T80_SQW_MAX_FREQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) return M41T80_SQW_MAX_FREQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (rate >= M41T80_SQW_MAX_FREQ / 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return M41T80_SQW_MAX_FREQ / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (!rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return 1 << ilog2(rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) struct i2c_client *client = m41t80->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) M41T80_REG_WDAY : M41T80_REG_SQW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) int reg, ret, val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (rate >= M41T80_SQW_MAX_FREQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) val = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) else if (rate >= M41T80_SQW_MAX_FREQ / 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) val = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) else if (rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) val = 15 - ilog2(rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) reg = i2c_smbus_read_byte_data(client, reg_sqw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (reg < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) reg = (reg & 0x0f) | (val << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) ret = i2c_smbus_write_byte_data(client, reg_sqw, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) m41t80->freq = m41t80_decode_freq(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) struct i2c_client *client = m41t80->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) ret |= M41T80_ALMON_SQWE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) ret &= ~M41T80_ALMON_SQWE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) m41t80->sqwe = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) static int m41t80_sqw_prepare(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return m41t80_sqw_control(hw, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) static void m41t80_sqw_unprepare(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) m41t80_sqw_control(hw, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) static int m41t80_sqw_is_prepared(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return sqw_to_m41t80_data(hw)->sqwe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static const struct clk_ops m41t80_sqw_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) .prepare = m41t80_sqw_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) .unprepare = m41t80_sqw_unprepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) .is_prepared = m41t80_sqw_is_prepared,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) .recalc_rate = m41t80_sqw_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) .round_rate = m41t80_sqw_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) .set_rate = m41t80_sqw_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct i2c_client *client = m41t80->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) struct device_node *node = client->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /* First disable the clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) ret & ~(M41T80_ALMON_SQWE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) init.name = "m41t80-sqw";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) init.ops = &m41t80_sqw_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) init.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) init.parent_names = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) init.num_parents = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) m41t80->sqw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) m41t80->freq = m41t80_get_freq(m41t80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) /* optional override of the clockname */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) of_property_read_string(node, "clock-output-names", &init.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) /* register the clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) clk = clk_register(&client->dev, &m41t80->sqw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (!IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) of_clk_add_provider(node, of_clk_src_simple_get, clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) return clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) #ifdef CONFIG_RTC_DRV_M41T80_WDT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) *****************************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) * Watchdog Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) *****************************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) static DEFINE_MUTEX(m41t80_rtc_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static struct i2c_client *save_client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) /* Default margin */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) #define WD_TIMO 60 /* 1..31 seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) static int wdt_margin = WD_TIMO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) module_param(wdt_margin, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 60s)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static unsigned long wdt_is_open;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) static int boot_flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) * wdt_ping:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) * Reload counter one with the watchdog timeout. We don't bother reloading
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) * the cascade counter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) static void wdt_ping(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) unsigned char i2c_data[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) struct i2c_msg msgs1[1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) .addr = save_client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) .len = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) .buf = i2c_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) struct m41t80_data *clientdata = i2c_get_clientdata(save_client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) i2c_data[0] = 0x09; /* watchdog register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (wdt_margin > 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) i2c_data[1] = (wdt_margin & 0xFC) | 0x83; /* resolution = 4s */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * WDS = 1 (0x80), mulitplier = WD_TIMO, resolution = 1s (0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) i2c_data[1] = wdt_margin << 2 | 0x82;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * M41T65 has three bits for watchdog resolution. Don't set bit 7, as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * that would be an invalid resolution.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (clientdata->features & M41T80_FEATURE_WD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) i2c_data[1] &= ~M41T80_WATCHDOG_RB2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) i2c_transfer(save_client->adapter, msgs1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) * wdt_disable:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * disables watchdog.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static void wdt_disable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) unsigned char i2c_data[2], i2c_buf[0x10];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) struct i2c_msg msgs0[2] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) .addr = save_client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) .len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) .buf = i2c_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) .addr = save_client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) .flags = I2C_M_RD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) .len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) .buf = i2c_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) struct i2c_msg msgs1[1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) .addr = save_client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) .len = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) .buf = i2c_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) i2c_data[0] = 0x09;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) i2c_transfer(save_client->adapter, msgs0, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) i2c_data[0] = 0x09;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) i2c_data[1] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) i2c_transfer(save_client->adapter, msgs1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * wdt_write:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) * @file: file handle to the watchdog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) * @buf: buffer to write (unused as data does not matter here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) * @count: count of bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * @ppos: pointer to the position to write. No seeks allowed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) * A write to a watchdog device is defined as a keepalive signal. Any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * write of data will do, as we we don't define content meaning.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) static ssize_t wdt_write(struct file *file, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) if (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) wdt_ping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static ssize_t wdt_read(struct file *file, char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) * wdt_ioctl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) * @file: file handle to the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) * @cmd: watchdog command
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) * @arg: argument pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) * The watchdog API defines a common set of functions for all watchdogs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) * according to their available features. We only actually usefully support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) * querying capabilities and current status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) static int wdt_ioctl(struct file *file, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) int new_margin, rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) static struct watchdog_info ident = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) .options = WDIOF_POWERUNDER | WDIOF_KEEPALIVEPING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) WDIOF_SETTIMEOUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) .firmware_version = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) .identity = "M41T80 WTD"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) case WDIOC_GETSUPPORT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) return copy_to_user((struct watchdog_info __user *)arg, &ident,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) sizeof(ident)) ? -EFAULT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) case WDIOC_GETSTATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) case WDIOC_GETBOOTSTATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return put_user(boot_flag, (int __user *)arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) case WDIOC_KEEPALIVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) wdt_ping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) case WDIOC_SETTIMEOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) if (get_user(new_margin, (int __user *)arg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) /* Arbitrary, can't find the card's limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (new_margin < 1 || new_margin > 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) wdt_margin = new_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) wdt_ping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) case WDIOC_GETTIMEOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) return put_user(wdt_margin, (int __user *)arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) case WDIOC_SETOPTIONS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) if (copy_from_user(&rv, (int __user *)arg, sizeof(int)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (rv & WDIOS_DISABLECARD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) pr_info("disable watchdog\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) wdt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) if (rv & WDIOS_ENABLECARD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) pr_info("enable watchdog\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) wdt_ping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) mutex_lock(&m41t80_rtc_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) ret = wdt_ioctl(file, cmd, arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) mutex_unlock(&m41t80_rtc_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) * wdt_open:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) * @inode: inode of device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) * @file: file handle to device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) static int wdt_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) mutex_lock(&m41t80_rtc_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (test_and_set_bit(0, &wdt_is_open)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) mutex_unlock(&m41t80_rtc_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) * Activate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) wdt_is_open = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) mutex_unlock(&m41t80_rtc_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) return stream_open(inode, file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) * wdt_close:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) * @inode: inode to board
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) * @file: file handle to board
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) static int wdt_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) if (MINOR(inode->i_rdev) == WATCHDOG_MINOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) clear_bit(0, &wdt_is_open);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) * notify_sys:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) * @this: our notifier block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) * @code: the event being reported
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) * @unused: unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) * Our notifier is called on system shutdowns. We want to turn the card
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) * off at reboot otherwise the machine will reboot again during memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) * test or worse yet during the following fsck. This would suck, in fact
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) * trust me - if it happens it does suck.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (code == SYS_DOWN || code == SYS_HALT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) /* Disable Watchdog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) wdt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) static const struct file_operations wdt_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) .read = wdt_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) .unlocked_ioctl = wdt_unlocked_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) .compat_ioctl = compat_ptr_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) .write = wdt_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) .open = wdt_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) .release = wdt_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) .llseek = no_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) static struct miscdevice wdt_dev = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) .minor = WATCHDOG_MINOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) .name = "watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) .fops = &wdt_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) * The WDT card needs to learn about soft shutdowns in order to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) * turn the timebomb registers off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) static struct notifier_block wdt_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) .notifier_call = wdt_notify_sys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) #endif /* CONFIG_RTC_DRV_M41T80_WDT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) *****************************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) * Driver Interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) *****************************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) static int m41t80_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) struct i2c_adapter *adapter = client->adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) struct rtc_time tm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) struct m41t80_data *m41t80_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) bool wakeup_source = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) I2C_FUNC_SMBUS_BYTE_DATA)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) dev_err(&adapter->dev, "doesn't support I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) m41t80_data = devm_kzalloc(&client->dev, sizeof(*m41t80_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) if (!m41t80_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) m41t80_data->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (client->dev.of_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) m41t80_data->features = (unsigned long)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) of_device_get_match_data(&client->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) m41t80_data->features = id->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) i2c_set_clientdata(client, m41t80_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) m41t80_data->rtc = devm_rtc_allocate_device(&client->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (IS_ERR(m41t80_data->rtc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return PTR_ERR(m41t80_data->rtc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) #ifdef CONFIG_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) wakeup_source = of_property_read_bool(client->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) "wakeup-source");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) if (client->irq > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) rc = devm_request_threaded_irq(&client->dev, client->irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) NULL, m41t80_handle_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) IRQF_TRIGGER_LOW | IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) "m41t80", client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) client->irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) wakeup_source = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) if (client->irq > 0 || wakeup_source) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) m41t80_rtc_ops.read_alarm = m41t80_read_alarm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) m41t80_rtc_ops.set_alarm = m41t80_set_alarm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) m41t80_rtc_ops.alarm_irq_enable = m41t80_alarm_irq_enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) /* Enable the wakealarm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) device_init_wakeup(&client->dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) m41t80_data->rtc->ops = &m41t80_rtc_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) m41t80_data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) m41t80_data->rtc->range_max = RTC_TIMESTAMP_END_2099;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) if (client->irq <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) /* We cannot support UIE mode if we do not have an IRQ line */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) m41t80_data->rtc->uie_unsupported = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) /* Make sure HT (Halt Update) bit is cleared */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) if (rc >= 0 && rc & M41T80_ALHOUR_HT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) if (m41t80_data->features & M41T80_FEATURE_HT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) m41t80_rtc_read_time(&client->dev, &tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) dev_info(&client->dev, "HT bit was set!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) dev_info(&client->dev, "Power Down at %ptR\n", &tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) rc & ~M41T80_ALHOUR_HT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) dev_err(&client->dev, "Can't clear HT bit\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) /* Make sure ST (stop) bit is cleared */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) if (rc >= 0 && rc & M41T80_SEC_ST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) rc & ~M41T80_SEC_ST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) if (rc < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) dev_err(&client->dev, "Can't clear ST bit\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) #ifdef CONFIG_RTC_DRV_M41T80_WDT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) if (m41t80_data->features & M41T80_FEATURE_HT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) save_client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) rc = misc_register(&wdt_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) rc = register_reboot_notifier(&wdt_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) misc_deregister(&wdt_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) #ifdef CONFIG_COMMON_CLK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (m41t80_data->features & M41T80_FEATURE_SQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) m41t80_sqw_register_clk(m41t80_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) rc = rtc_register_device(m41t80_data->rtc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) static int m41t80_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) #ifdef CONFIG_RTC_DRV_M41T80_WDT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) struct m41t80_data *clientdata = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) if (clientdata->features & M41T80_FEATURE_HT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) misc_deregister(&wdt_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) unregister_reboot_notifier(&wdt_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) static struct i2c_driver m41t80_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) .name = "rtc-m41t80",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) .of_match_table = of_match_ptr(m41t80_of_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) .pm = &m41t80_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) .probe = m41t80_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) .remove = m41t80_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) .id_table = m41t80_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) module_i2c_driver(m41t80_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) MODULE_LICENSE("GPL");