1e6e7376cSAlexandre Belloni // SPDX-License-Identifier: GPL-2.0 2e6e7376cSAlexandre Belloni /* 3e6e7376cSAlexandre Belloni * RTC driver for the Micro Crystal RV3028 4e6e7376cSAlexandre Belloni * 5e6e7376cSAlexandre Belloni * Copyright (C) 2019 Micro Crystal SA 6e6e7376cSAlexandre Belloni * 7e6e7376cSAlexandre Belloni * Alexandre Belloni <alexandre.belloni@bootlin.com> 8e6e7376cSAlexandre Belloni * 9e6e7376cSAlexandre Belloni */ 10e6e7376cSAlexandre Belloni 11f583c341SParthiban Nallathambi #include <linux/clk-provider.h> 12e6e7376cSAlexandre Belloni #include <linux/bcd.h> 13018d959bSAlexandre Belloni #include <linux/bitfield.h> 14e6e7376cSAlexandre Belloni #include <linux/bitops.h> 15e6e7376cSAlexandre Belloni #include <linux/i2c.h> 16e6e7376cSAlexandre Belloni #include <linux/interrupt.h> 17e6e7376cSAlexandre Belloni #include <linux/kernel.h> 18e6e7376cSAlexandre Belloni #include <linux/log2.h> 19e6e7376cSAlexandre Belloni #include <linux/module.h> 20*48144c28SRob Herring #include <linux/of.h> 21e6e7376cSAlexandre Belloni #include <linux/regmap.h> 22e6e7376cSAlexandre Belloni #include <linux/rtc.h> 23e6e7376cSAlexandre Belloni 24e6e7376cSAlexandre Belloni #define RV3028_SEC 0x00 25e6e7376cSAlexandre Belloni #define RV3028_MIN 0x01 26e6e7376cSAlexandre Belloni #define RV3028_HOUR 0x02 27e6e7376cSAlexandre Belloni #define RV3028_WDAY 0x03 28e6e7376cSAlexandre Belloni #define RV3028_DAY 0x04 29e6e7376cSAlexandre Belloni #define RV3028_MONTH 0x05 30e6e7376cSAlexandre Belloni #define RV3028_YEAR 0x06 31e6e7376cSAlexandre Belloni #define RV3028_ALARM_MIN 0x07 32e6e7376cSAlexandre Belloni #define RV3028_ALARM_HOUR 0x08 33e6e7376cSAlexandre Belloni #define RV3028_ALARM_DAY 0x09 34e6e7376cSAlexandre Belloni #define RV3028_STATUS 0x0E 35e6e7376cSAlexandre Belloni #define RV3028_CTRL1 0x0F 36e6e7376cSAlexandre Belloni #define RV3028_CTRL2 0x10 37e6e7376cSAlexandre Belloni #define RV3028_EVT_CTRL 0x13 38e6e7376cSAlexandre Belloni #define RV3028_TS_COUNT 0x14 39e6e7376cSAlexandre Belloni #define RV3028_TS_SEC 0x15 40e6e7376cSAlexandre Belloni #define RV3028_RAM1 0x1F 41e6e7376cSAlexandre Belloni #define RV3028_EEPROM_ADDR 0x25 42e6e7376cSAlexandre Belloni #define RV3028_EEPROM_DATA 0x26 43e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD 0x27 44e6e7376cSAlexandre Belloni #define RV3028_CLKOUT 0x35 45e6e7376cSAlexandre Belloni #define RV3028_OFFSET 0x36 46e6e7376cSAlexandre Belloni #define RV3028_BACKUP 0x37 47e6e7376cSAlexandre Belloni 48e6e7376cSAlexandre Belloni #define RV3028_STATUS_PORF BIT(0) 49e6e7376cSAlexandre Belloni #define RV3028_STATUS_EVF BIT(1) 50e6e7376cSAlexandre Belloni #define RV3028_STATUS_AF BIT(2) 51e6e7376cSAlexandre Belloni #define RV3028_STATUS_TF BIT(3) 52e6e7376cSAlexandre Belloni #define RV3028_STATUS_UF BIT(4) 53e6e7376cSAlexandre Belloni #define RV3028_STATUS_BSF BIT(5) 54e6e7376cSAlexandre Belloni #define RV3028_STATUS_CLKF BIT(6) 55e6e7376cSAlexandre Belloni #define RV3028_STATUS_EEBUSY BIT(7) 56e6e7376cSAlexandre Belloni 57f583c341SParthiban Nallathambi #define RV3028_CLKOUT_FD_MASK GENMASK(2, 0) 58f583c341SParthiban Nallathambi #define RV3028_CLKOUT_PORIE BIT(3) 59f583c341SParthiban Nallathambi #define RV3028_CLKOUT_CLKSY BIT(6) 60f583c341SParthiban Nallathambi #define RV3028_CLKOUT_CLKOE BIT(7) 61f583c341SParthiban Nallathambi 62e6e7376cSAlexandre Belloni #define RV3028_CTRL1_EERD BIT(3) 63e6e7376cSAlexandre Belloni #define RV3028_CTRL1_WADA BIT(5) 64e6e7376cSAlexandre Belloni 65e6e7376cSAlexandre Belloni #define RV3028_CTRL2_RESET BIT(0) 66e6e7376cSAlexandre Belloni #define RV3028_CTRL2_12_24 BIT(1) 67e6e7376cSAlexandre Belloni #define RV3028_CTRL2_EIE BIT(2) 68e6e7376cSAlexandre Belloni #define RV3028_CTRL2_AIE BIT(3) 69e6e7376cSAlexandre Belloni #define RV3028_CTRL2_TIE BIT(4) 70e6e7376cSAlexandre Belloni #define RV3028_CTRL2_UIE BIT(5) 71e6e7376cSAlexandre Belloni #define RV3028_CTRL2_TSE BIT(7) 72e6e7376cSAlexandre Belloni 73e6e7376cSAlexandre Belloni #define RV3028_EVT_CTRL_TSR BIT(2) 74e6e7376cSAlexandre Belloni 75024e6f3dSAlexandre Belloni #define RV3028_EEPROM_CMD_UPDATE 0x11 76e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD_WRITE 0x21 77e6e7376cSAlexandre Belloni #define RV3028_EEPROM_CMD_READ 0x22 78e6e7376cSAlexandre Belloni 79e6e7376cSAlexandre Belloni #define RV3028_EEBUSY_POLL 10000 80e6e7376cSAlexandre Belloni #define RV3028_EEBUSY_TIMEOUT 100000 81e6e7376cSAlexandre Belloni 82e6e7376cSAlexandre Belloni #define RV3028_BACKUP_TCE BIT(5) 83e6e7376cSAlexandre Belloni #define RV3028_BACKUP_TCR_MASK GENMASK(1,0) 84018d959bSAlexandre Belloni #define RV3028_BACKUP_BSM GENMASK(3,2) 85018d959bSAlexandre Belloni 86018d959bSAlexandre Belloni #define RV3028_BACKUP_BSM_DSM 0x1 87018d959bSAlexandre Belloni #define RV3028_BACKUP_BSM_LSM 0x3 88e6e7376cSAlexandre Belloni 89e6e7376cSAlexandre Belloni #define OFFSET_STEP_PPT 953674 90e6e7376cSAlexandre Belloni 91e6e7376cSAlexandre Belloni enum rv3028_type { 92e6e7376cSAlexandre Belloni rv_3028, 93e6e7376cSAlexandre Belloni }; 94e6e7376cSAlexandre Belloni 95e6e7376cSAlexandre Belloni struct rv3028_data { 96e6e7376cSAlexandre Belloni struct regmap *regmap; 97e6e7376cSAlexandre Belloni struct rtc_device *rtc; 98e6e7376cSAlexandre Belloni enum rv3028_type type; 99f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK 100f583c341SParthiban Nallathambi struct clk_hw clkout_hw; 101f583c341SParthiban Nallathambi #endif 102e6e7376cSAlexandre Belloni }; 103e6e7376cSAlexandre Belloni 104c1efae14SAlexandre Belloni static u16 rv3028_trickle_resistors[] = {3000, 5000, 9000, 15000}; 105e6e7376cSAlexandre Belloni 106e6e7376cSAlexandre Belloni static ssize_t timestamp0_store(struct device *dev, 107e6e7376cSAlexandre Belloni struct device_attribute *attr, 108e6e7376cSAlexandre Belloni const char *buf, size_t count) 109e6e7376cSAlexandre Belloni { 110e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent); 111e6e7376cSAlexandre Belloni 112e6e7376cSAlexandre Belloni regmap_update_bits(rv3028->regmap, RV3028_EVT_CTRL, RV3028_EVT_CTRL_TSR, 113e6e7376cSAlexandre Belloni RV3028_EVT_CTRL_TSR); 114e6e7376cSAlexandre Belloni 115e6e7376cSAlexandre Belloni return count; 116e6e7376cSAlexandre Belloni }; 117e6e7376cSAlexandre Belloni 118e6e7376cSAlexandre Belloni static ssize_t timestamp0_show(struct device *dev, 119e6e7376cSAlexandre Belloni struct device_attribute *attr, char *buf) 120e6e7376cSAlexandre Belloni { 121e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent); 122e6e7376cSAlexandre Belloni struct rtc_time tm; 123e6e7376cSAlexandre Belloni int ret, count; 124e6e7376cSAlexandre Belloni u8 date[6]; 125e6e7376cSAlexandre Belloni 126e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count); 127e6e7376cSAlexandre Belloni if (ret) 128e6e7376cSAlexandre Belloni return ret; 129e6e7376cSAlexandre Belloni 130e6e7376cSAlexandre Belloni if (!count) 131e6e7376cSAlexandre Belloni return 0; 132e6e7376cSAlexandre Belloni 133e6e7376cSAlexandre Belloni ret = regmap_bulk_read(rv3028->regmap, RV3028_TS_SEC, date, 134e6e7376cSAlexandre Belloni sizeof(date)); 135e6e7376cSAlexandre Belloni if (ret) 136e6e7376cSAlexandre Belloni return ret; 137e6e7376cSAlexandre Belloni 138e6e7376cSAlexandre Belloni tm.tm_sec = bcd2bin(date[0]); 139e6e7376cSAlexandre Belloni tm.tm_min = bcd2bin(date[1]); 140e6e7376cSAlexandre Belloni tm.tm_hour = bcd2bin(date[2]); 141e6e7376cSAlexandre Belloni tm.tm_mday = bcd2bin(date[3]); 142e6e7376cSAlexandre Belloni tm.tm_mon = bcd2bin(date[4]) - 1; 143e6e7376cSAlexandre Belloni tm.tm_year = bcd2bin(date[5]) + 100; 144e6e7376cSAlexandre Belloni 145e6e7376cSAlexandre Belloni ret = rtc_valid_tm(&tm); 146e6e7376cSAlexandre Belloni if (ret) 147e6e7376cSAlexandre Belloni return ret; 148e6e7376cSAlexandre Belloni 149e6e7376cSAlexandre Belloni return sprintf(buf, "%llu\n", 150e6e7376cSAlexandre Belloni (unsigned long long)rtc_tm_to_time64(&tm)); 151e6e7376cSAlexandre Belloni }; 152e6e7376cSAlexandre Belloni 153e6e7376cSAlexandre Belloni static DEVICE_ATTR_RW(timestamp0); 154e6e7376cSAlexandre Belloni 155e6e7376cSAlexandre Belloni static ssize_t timestamp0_count_show(struct device *dev, 156e6e7376cSAlexandre Belloni struct device_attribute *attr, char *buf) 157e6e7376cSAlexandre Belloni { 158e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent); 159e6e7376cSAlexandre Belloni int ret, count; 160e6e7376cSAlexandre Belloni 161e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count); 162e6e7376cSAlexandre Belloni if (ret) 163e6e7376cSAlexandre Belloni return ret; 164e6e7376cSAlexandre Belloni 165e6e7376cSAlexandre Belloni return sprintf(buf, "%u\n", count); 166e6e7376cSAlexandre Belloni }; 167e6e7376cSAlexandre Belloni 168e6e7376cSAlexandre Belloni static DEVICE_ATTR_RO(timestamp0_count); 169e6e7376cSAlexandre Belloni 170e6e7376cSAlexandre Belloni static struct attribute *rv3028_attrs[] = { 171e6e7376cSAlexandre Belloni &dev_attr_timestamp0.attr, 172e6e7376cSAlexandre Belloni &dev_attr_timestamp0_count.attr, 173e6e7376cSAlexandre Belloni NULL 174e6e7376cSAlexandre Belloni }; 175e6e7376cSAlexandre Belloni 176e6e7376cSAlexandre Belloni static const struct attribute_group rv3028_attr_group = { 177e6e7376cSAlexandre Belloni .attrs = rv3028_attrs, 178e6e7376cSAlexandre Belloni }; 179e6e7376cSAlexandre Belloni 180de0ad60eSAlexandre Belloni static int rv3028_exit_eerd(struct rv3028_data *rv3028, u32 eerd) 181de0ad60eSAlexandre Belloni { 182de0ad60eSAlexandre Belloni if (eerd) 183de0ad60eSAlexandre Belloni return 0; 184de0ad60eSAlexandre Belloni 185de0ad60eSAlexandre Belloni return regmap_update_bits(rv3028->regmap, RV3028_CTRL1, RV3028_CTRL1_EERD, 0); 186de0ad60eSAlexandre Belloni } 187de0ad60eSAlexandre Belloni 188de0ad60eSAlexandre Belloni static int rv3028_enter_eerd(struct rv3028_data *rv3028, u32 *eerd) 189de0ad60eSAlexandre Belloni { 190de0ad60eSAlexandre Belloni u32 ctrl1, status; 191de0ad60eSAlexandre Belloni int ret; 192de0ad60eSAlexandre Belloni 193de0ad60eSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_CTRL1, &ctrl1); 194de0ad60eSAlexandre Belloni if (ret) 195de0ad60eSAlexandre Belloni return ret; 196de0ad60eSAlexandre Belloni 197de0ad60eSAlexandre Belloni *eerd = ctrl1 & RV3028_CTRL1_EERD; 198de0ad60eSAlexandre Belloni if (*eerd) 199de0ad60eSAlexandre Belloni return 0; 200de0ad60eSAlexandre Belloni 201de0ad60eSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1, 202de0ad60eSAlexandre Belloni RV3028_CTRL1_EERD, RV3028_CTRL1_EERD); 203de0ad60eSAlexandre Belloni if (ret) 204de0ad60eSAlexandre Belloni return ret; 205de0ad60eSAlexandre Belloni 206de0ad60eSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, 207de0ad60eSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY), 208de0ad60eSAlexandre Belloni RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); 209de0ad60eSAlexandre Belloni if (ret) { 210de0ad60eSAlexandre Belloni rv3028_exit_eerd(rv3028, *eerd); 211de0ad60eSAlexandre Belloni 212de0ad60eSAlexandre Belloni return ret; 213de0ad60eSAlexandre Belloni } 214de0ad60eSAlexandre Belloni 215de0ad60eSAlexandre Belloni return 0; 216de0ad60eSAlexandre Belloni } 217de0ad60eSAlexandre Belloni 218024e6f3dSAlexandre Belloni static int rv3028_update_eeprom(struct rv3028_data *rv3028, u32 eerd) 219024e6f3dSAlexandre Belloni { 220024e6f3dSAlexandre Belloni u32 status; 221024e6f3dSAlexandre Belloni int ret; 222024e6f3dSAlexandre Belloni 223024e6f3dSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0); 224024e6f3dSAlexandre Belloni if (ret) 225024e6f3dSAlexandre Belloni goto exit_eerd; 226024e6f3dSAlexandre Belloni 227024e6f3dSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, RV3028_EEPROM_CMD_UPDATE); 228024e6f3dSAlexandre Belloni if (ret) 229024e6f3dSAlexandre Belloni goto exit_eerd; 230024e6f3dSAlexandre Belloni 231024e6f3dSAlexandre Belloni usleep_range(63000, RV3028_EEBUSY_TIMEOUT); 232024e6f3dSAlexandre Belloni 233024e6f3dSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, 234024e6f3dSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY), 235024e6f3dSAlexandre Belloni RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); 236024e6f3dSAlexandre Belloni 237024e6f3dSAlexandre Belloni exit_eerd: 238024e6f3dSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd); 239024e6f3dSAlexandre Belloni 240024e6f3dSAlexandre Belloni return ret; 241024e6f3dSAlexandre Belloni } 242024e6f3dSAlexandre Belloni 243024e6f3dSAlexandre Belloni static int rv3028_update_cfg(struct rv3028_data *rv3028, unsigned int reg, 244024e6f3dSAlexandre Belloni unsigned int mask, unsigned int val) 245024e6f3dSAlexandre Belloni { 246024e6f3dSAlexandre Belloni u32 eerd; 247024e6f3dSAlexandre Belloni int ret; 248024e6f3dSAlexandre Belloni 249024e6f3dSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd); 250024e6f3dSAlexandre Belloni if (ret) 251024e6f3dSAlexandre Belloni return ret; 252024e6f3dSAlexandre Belloni 253024e6f3dSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, reg, mask, val); 254024e6f3dSAlexandre Belloni if (ret) { 255024e6f3dSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd); 256024e6f3dSAlexandre Belloni return ret; 257024e6f3dSAlexandre Belloni } 258024e6f3dSAlexandre Belloni 259024e6f3dSAlexandre Belloni return rv3028_update_eeprom(rv3028, eerd); 260024e6f3dSAlexandre Belloni } 261024e6f3dSAlexandre Belloni 262e6e7376cSAlexandre Belloni static irqreturn_t rv3028_handle_irq(int irq, void *dev_id) 263e6e7376cSAlexandre Belloni { 264e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_id; 265e6e7376cSAlexandre Belloni unsigned long events = 0; 266e6e7376cSAlexandre Belloni u32 status = 0, ctrl = 0; 267e6e7376cSAlexandre Belloni 268e6e7376cSAlexandre Belloni if (regmap_read(rv3028->regmap, RV3028_STATUS, &status) < 0 || 269e6e7376cSAlexandre Belloni status == 0) { 270e6e7376cSAlexandre Belloni return IRQ_NONE; 271e6e7376cSAlexandre Belloni } 272e6e7376cSAlexandre Belloni 273f007c479SAlexandre Belloni status &= ~RV3028_STATUS_PORF; 274f007c479SAlexandre Belloni 275e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_TF) { 276e6e7376cSAlexandre Belloni status |= RV3028_STATUS_TF; 277e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_TIE; 278e6e7376cSAlexandre Belloni events |= RTC_PF; 279e6e7376cSAlexandre Belloni } 280e6e7376cSAlexandre Belloni 281e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_AF) { 282e6e7376cSAlexandre Belloni status |= RV3028_STATUS_AF; 283e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_AIE; 284e6e7376cSAlexandre Belloni events |= RTC_AF; 285e6e7376cSAlexandre Belloni } 286e6e7376cSAlexandre Belloni 287e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_UF) { 288e6e7376cSAlexandre Belloni status |= RV3028_STATUS_UF; 289e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_UIE; 290e6e7376cSAlexandre Belloni events |= RTC_UF; 291e6e7376cSAlexandre Belloni } 292e6e7376cSAlexandre Belloni 293e6e7376cSAlexandre Belloni if (events) { 294e6e7376cSAlexandre Belloni rtc_update_irq(rv3028->rtc, 1, events); 295e6e7376cSAlexandre Belloni regmap_update_bits(rv3028->regmap, RV3028_STATUS, status, 0); 296e6e7376cSAlexandre Belloni regmap_update_bits(rv3028->regmap, RV3028_CTRL2, ctrl, 0); 297e6e7376cSAlexandre Belloni } 298e6e7376cSAlexandre Belloni 299e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_EVF) { 300e6e7376cSAlexandre Belloni sysfs_notify(&rv3028->rtc->dev.kobj, NULL, 301e6e7376cSAlexandre Belloni dev_attr_timestamp0.attr.name); 302e6e7376cSAlexandre Belloni dev_warn(&rv3028->rtc->dev, "event detected"); 303e6e7376cSAlexandre Belloni } 304e6e7376cSAlexandre Belloni 305e6e7376cSAlexandre Belloni return IRQ_HANDLED; 306e6e7376cSAlexandre Belloni } 307e6e7376cSAlexandre Belloni 308e6e7376cSAlexandre Belloni static int rv3028_get_time(struct device *dev, struct rtc_time *tm) 309e6e7376cSAlexandre Belloni { 310e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 311e6e7376cSAlexandre Belloni u8 date[7]; 312e6e7376cSAlexandre Belloni int ret, status; 313e6e7376cSAlexandre Belloni 314e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status); 315e6e7376cSAlexandre Belloni if (ret < 0) 316e6e7376cSAlexandre Belloni return ret; 317e6e7376cSAlexandre Belloni 318c37b6430SAlexandre Belloni if (status & RV3028_STATUS_PORF) 319e6e7376cSAlexandre Belloni return -EINVAL; 320e6e7376cSAlexandre Belloni 321e6e7376cSAlexandre Belloni ret = regmap_bulk_read(rv3028->regmap, RV3028_SEC, date, sizeof(date)); 322e6e7376cSAlexandre Belloni if (ret) 323e6e7376cSAlexandre Belloni return ret; 324e6e7376cSAlexandre Belloni 325e6e7376cSAlexandre Belloni tm->tm_sec = bcd2bin(date[RV3028_SEC] & 0x7f); 326e6e7376cSAlexandre Belloni tm->tm_min = bcd2bin(date[RV3028_MIN] & 0x7f); 327e6e7376cSAlexandre Belloni tm->tm_hour = bcd2bin(date[RV3028_HOUR] & 0x3f); 3286e00b6d0SHeiko Schocher tm->tm_wday = date[RV3028_WDAY] & 0x7f; 329e6e7376cSAlexandre Belloni tm->tm_mday = bcd2bin(date[RV3028_DAY] & 0x3f); 330e6e7376cSAlexandre Belloni tm->tm_mon = bcd2bin(date[RV3028_MONTH] & 0x1f) - 1; 331e6e7376cSAlexandre Belloni tm->tm_year = bcd2bin(date[RV3028_YEAR]) + 100; 332e6e7376cSAlexandre Belloni 333e6e7376cSAlexandre Belloni return 0; 334e6e7376cSAlexandre Belloni } 335e6e7376cSAlexandre Belloni 336e6e7376cSAlexandre Belloni static int rv3028_set_time(struct device *dev, struct rtc_time *tm) 337e6e7376cSAlexandre Belloni { 338e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 339e6e7376cSAlexandre Belloni u8 date[7]; 340e6e7376cSAlexandre Belloni int ret; 341e6e7376cSAlexandre Belloni 342e6e7376cSAlexandre Belloni date[RV3028_SEC] = bin2bcd(tm->tm_sec); 343e6e7376cSAlexandre Belloni date[RV3028_MIN] = bin2bcd(tm->tm_min); 344e6e7376cSAlexandre Belloni date[RV3028_HOUR] = bin2bcd(tm->tm_hour); 3456e00b6d0SHeiko Schocher date[RV3028_WDAY] = tm->tm_wday; 346e6e7376cSAlexandre Belloni date[RV3028_DAY] = bin2bcd(tm->tm_mday); 347e6e7376cSAlexandre Belloni date[RV3028_MONTH] = bin2bcd(tm->tm_mon + 1); 348e6e7376cSAlexandre Belloni date[RV3028_YEAR] = bin2bcd(tm->tm_year - 100); 349e6e7376cSAlexandre Belloni 350e6e7376cSAlexandre Belloni /* 351e6e7376cSAlexandre Belloni * Writing to the Seconds register has the same effect as setting RESET 352e6e7376cSAlexandre Belloni * bit to 1 353e6e7376cSAlexandre Belloni */ 354e6e7376cSAlexandre Belloni ret = regmap_bulk_write(rv3028->regmap, RV3028_SEC, date, 355e6e7376cSAlexandre Belloni sizeof(date)); 356e6e7376cSAlexandre Belloni if (ret) 357e6e7376cSAlexandre Belloni return ret; 358e6e7376cSAlexandre Belloni 359e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS, 360e6e7376cSAlexandre Belloni RV3028_STATUS_PORF, 0); 361e6e7376cSAlexandre Belloni 362e6e7376cSAlexandre Belloni return ret; 363e6e7376cSAlexandre Belloni } 364e6e7376cSAlexandre Belloni 365e6e7376cSAlexandre Belloni static int rv3028_get_alarm(struct device *dev, struct rtc_wkalrm *alrm) 366e6e7376cSAlexandre Belloni { 367e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 368e6e7376cSAlexandre Belloni u8 alarmvals[3]; 369e6e7376cSAlexandre Belloni int status, ctrl, ret; 370e6e7376cSAlexandre Belloni 371e6e7376cSAlexandre Belloni ret = regmap_bulk_read(rv3028->regmap, RV3028_ALARM_MIN, alarmvals, 372e6e7376cSAlexandre Belloni sizeof(alarmvals)); 373e6e7376cSAlexandre Belloni if (ret) 374e6e7376cSAlexandre Belloni return ret; 375e6e7376cSAlexandre Belloni 376e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status); 377e6e7376cSAlexandre Belloni if (ret < 0) 378e6e7376cSAlexandre Belloni return ret; 379e6e7376cSAlexandre Belloni 380e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_CTRL2, &ctrl); 381e6e7376cSAlexandre Belloni if (ret < 0) 382e6e7376cSAlexandre Belloni return ret; 383e6e7376cSAlexandre Belloni 384e6e7376cSAlexandre Belloni alrm->time.tm_sec = 0; 385e6e7376cSAlexandre Belloni alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f); 386e6e7376cSAlexandre Belloni alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f); 387e6e7376cSAlexandre Belloni alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f); 388e6e7376cSAlexandre Belloni 389e6e7376cSAlexandre Belloni alrm->enabled = !!(ctrl & RV3028_CTRL2_AIE); 390e6e7376cSAlexandre Belloni alrm->pending = (status & RV3028_STATUS_AF) && alrm->enabled; 391e6e7376cSAlexandre Belloni 392e6e7376cSAlexandre Belloni return 0; 393e6e7376cSAlexandre Belloni } 394e6e7376cSAlexandre Belloni 395e6e7376cSAlexandre Belloni static int rv3028_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 396e6e7376cSAlexandre Belloni { 397e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 398e6e7376cSAlexandre Belloni u8 alarmvals[3]; 399e6e7376cSAlexandre Belloni u8 ctrl = 0; 400e6e7376cSAlexandre Belloni int ret; 401e6e7376cSAlexandre Belloni 402e6e7376cSAlexandre Belloni /* The alarm has no seconds, round up to nearest minute */ 403e6e7376cSAlexandre Belloni if (alrm->time.tm_sec) { 404e6e7376cSAlexandre Belloni time64_t alarm_time = rtc_tm_to_time64(&alrm->time); 405e6e7376cSAlexandre Belloni 406e6e7376cSAlexandre Belloni alarm_time += 60 - alrm->time.tm_sec; 407e6e7376cSAlexandre Belloni rtc_time64_to_tm(alarm_time, &alrm->time); 408e6e7376cSAlexandre Belloni } 409e6e7376cSAlexandre Belloni 410e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2, 411e6e7376cSAlexandre Belloni RV3028_CTRL2_AIE | RV3028_CTRL2_UIE, 0); 412e6e7376cSAlexandre Belloni if (ret) 413e6e7376cSAlexandre Belloni return ret; 414e6e7376cSAlexandre Belloni 415e6e7376cSAlexandre Belloni alarmvals[0] = bin2bcd(alrm->time.tm_min); 416e6e7376cSAlexandre Belloni alarmvals[1] = bin2bcd(alrm->time.tm_hour); 417e6e7376cSAlexandre Belloni alarmvals[2] = bin2bcd(alrm->time.tm_mday); 418e6e7376cSAlexandre Belloni 419e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS, 420e6e7376cSAlexandre Belloni RV3028_STATUS_AF, 0); 421e6e7376cSAlexandre Belloni if (ret) 422e6e7376cSAlexandre Belloni return ret; 423e6e7376cSAlexandre Belloni 424e6e7376cSAlexandre Belloni ret = regmap_bulk_write(rv3028->regmap, RV3028_ALARM_MIN, alarmvals, 425e6e7376cSAlexandre Belloni sizeof(alarmvals)); 426e6e7376cSAlexandre Belloni if (ret) 427e6e7376cSAlexandre Belloni return ret; 428e6e7376cSAlexandre Belloni 429e6e7376cSAlexandre Belloni if (alrm->enabled) { 430e6e7376cSAlexandre Belloni if (rv3028->rtc->uie_rtctimer.enabled) 431e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_UIE; 432e6e7376cSAlexandre Belloni if (rv3028->rtc->aie_timer.enabled) 433e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_AIE; 434e6e7376cSAlexandre Belloni } 435e6e7376cSAlexandre Belloni 436e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2, 437e6e7376cSAlexandre Belloni RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl); 438e6e7376cSAlexandre Belloni 439e6e7376cSAlexandre Belloni return ret; 440e6e7376cSAlexandre Belloni } 441e6e7376cSAlexandre Belloni 442e6e7376cSAlexandre Belloni static int rv3028_alarm_irq_enable(struct device *dev, unsigned int enabled) 443e6e7376cSAlexandre Belloni { 444e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 445e6e7376cSAlexandre Belloni int ctrl = 0, ret; 446e6e7376cSAlexandre Belloni 447e6e7376cSAlexandre Belloni if (enabled) { 448e6e7376cSAlexandre Belloni if (rv3028->rtc->uie_rtctimer.enabled) 449e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_UIE; 450e6e7376cSAlexandre Belloni if (rv3028->rtc->aie_timer.enabled) 451e6e7376cSAlexandre Belloni ctrl |= RV3028_CTRL2_AIE; 452e6e7376cSAlexandre Belloni } 453e6e7376cSAlexandre Belloni 454e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS, 455e6e7376cSAlexandre Belloni RV3028_STATUS_AF | RV3028_STATUS_UF, 0); 456e6e7376cSAlexandre Belloni if (ret) 457e6e7376cSAlexandre Belloni return ret; 458e6e7376cSAlexandre Belloni 459e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2, 460e6e7376cSAlexandre Belloni RV3028_CTRL2_UIE | RV3028_CTRL2_AIE, ctrl); 461e6e7376cSAlexandre Belloni if (ret) 462e6e7376cSAlexandre Belloni return ret; 463e6e7376cSAlexandre Belloni 464e6e7376cSAlexandre Belloni return 0; 465e6e7376cSAlexandre Belloni } 466e6e7376cSAlexandre Belloni 467e6e7376cSAlexandre Belloni static int rv3028_read_offset(struct device *dev, long *offset) 468e6e7376cSAlexandre Belloni { 469e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 470e6e7376cSAlexandre Belloni int ret, value, steps; 471e6e7376cSAlexandre Belloni 472e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_OFFSET, &value); 473e6e7376cSAlexandre Belloni if (ret < 0) 474e6e7376cSAlexandre Belloni return ret; 475e6e7376cSAlexandre Belloni 476e6e7376cSAlexandre Belloni steps = sign_extend32(value << 1, 8); 477e6e7376cSAlexandre Belloni 478e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value); 479e6e7376cSAlexandre Belloni if (ret < 0) 480e6e7376cSAlexandre Belloni return ret; 481e6e7376cSAlexandre Belloni 482e6e7376cSAlexandre Belloni steps += value >> 7; 483e6e7376cSAlexandre Belloni 484e6e7376cSAlexandre Belloni *offset = DIV_ROUND_CLOSEST(steps * OFFSET_STEP_PPT, 1000); 485e6e7376cSAlexandre Belloni 486e6e7376cSAlexandre Belloni return 0; 487e6e7376cSAlexandre Belloni } 488e6e7376cSAlexandre Belloni 489e6e7376cSAlexandre Belloni static int rv3028_set_offset(struct device *dev, long offset) 490e6e7376cSAlexandre Belloni { 491e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 492024e6f3dSAlexandre Belloni u32 eerd; 493e6e7376cSAlexandre Belloni int ret; 494e6e7376cSAlexandre Belloni 495e6e7376cSAlexandre Belloni offset = clamp(offset, -244141L, 243187L) * 1000; 496e6e7376cSAlexandre Belloni offset = DIV_ROUND_CLOSEST(offset, OFFSET_STEP_PPT); 497e6e7376cSAlexandre Belloni 498024e6f3dSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd); 499024e6f3dSAlexandre Belloni if (ret) 500e6e7376cSAlexandre Belloni return ret; 501e6e7376cSAlexandre Belloni 502024e6f3dSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_OFFSET, offset >> 1); 503024e6f3dSAlexandre Belloni if (ret < 0) 504024e6f3dSAlexandre Belloni goto exit_eerd; 505024e6f3dSAlexandre Belloni 506024e6f3dSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP, BIT(7), 507e6e7376cSAlexandre Belloni offset << 7); 508024e6f3dSAlexandre Belloni if (ret < 0) 509024e6f3dSAlexandre Belloni goto exit_eerd; 510024e6f3dSAlexandre Belloni 511024e6f3dSAlexandre Belloni return rv3028_update_eeprom(rv3028, eerd); 512024e6f3dSAlexandre Belloni 513024e6f3dSAlexandre Belloni exit_eerd: 514024e6f3dSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd); 515024e6f3dSAlexandre Belloni 516024e6f3dSAlexandre Belloni return ret; 517024e6f3dSAlexandre Belloni 518e6e7376cSAlexandre Belloni } 519e6e7376cSAlexandre Belloni 520018d959bSAlexandre Belloni static int rv3028_param_get(struct device *dev, struct rtc_param *param) 521018d959bSAlexandre Belloni { 522018d959bSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 523018d959bSAlexandre Belloni int ret; 524018d959bSAlexandre Belloni u32 value; 525018d959bSAlexandre Belloni 526e5f12a39SKe Sun switch(param->param) { 527018d959bSAlexandre Belloni case RTC_PARAM_BACKUP_SWITCH_MODE: 528018d959bSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &value); 529018d959bSAlexandre Belloni if (ret < 0) 530018d959bSAlexandre Belloni return ret; 531018d959bSAlexandre Belloni 532018d959bSAlexandre Belloni value = FIELD_GET(RV3028_BACKUP_BSM, value); 533018d959bSAlexandre Belloni 534018d959bSAlexandre Belloni switch(value) { 535018d959bSAlexandre Belloni case RV3028_BACKUP_BSM_DSM: 536018d959bSAlexandre Belloni param->uvalue = RTC_BSM_DIRECT; 537018d959bSAlexandre Belloni break; 538018d959bSAlexandre Belloni case RV3028_BACKUP_BSM_LSM: 539018d959bSAlexandre Belloni param->uvalue = RTC_BSM_LEVEL; 540018d959bSAlexandre Belloni break; 541018d959bSAlexandre Belloni default: 542018d959bSAlexandre Belloni param->uvalue = RTC_BSM_DISABLED; 543018d959bSAlexandre Belloni } 544018d959bSAlexandre Belloni break; 545018d959bSAlexandre Belloni 546018d959bSAlexandre Belloni default: 547018d959bSAlexandre Belloni return -EINVAL; 548018d959bSAlexandre Belloni } 549018d959bSAlexandre Belloni 550018d959bSAlexandre Belloni return 0; 551018d959bSAlexandre Belloni } 552018d959bSAlexandre Belloni 553018d959bSAlexandre Belloni static int rv3028_param_set(struct device *dev, struct rtc_param *param) 554018d959bSAlexandre Belloni { 555018d959bSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 556e5f12a39SKe Sun u8 mode; 557018d959bSAlexandre Belloni 558018d959bSAlexandre Belloni switch(param->param) { 559018d959bSAlexandre Belloni case RTC_PARAM_BACKUP_SWITCH_MODE: 560018d959bSAlexandre Belloni switch (param->uvalue) { 561018d959bSAlexandre Belloni case RTC_BSM_DISABLED: 562018d959bSAlexandre Belloni mode = 0; 563018d959bSAlexandre Belloni break; 564018d959bSAlexandre Belloni case RTC_BSM_DIRECT: 565018d959bSAlexandre Belloni mode = RV3028_BACKUP_BSM_DSM; 566018d959bSAlexandre Belloni break; 567018d959bSAlexandre Belloni case RTC_BSM_LEVEL: 568018d959bSAlexandre Belloni mode = RV3028_BACKUP_BSM_LSM; 569018d959bSAlexandre Belloni break; 570018d959bSAlexandre Belloni default: 571018d959bSAlexandre Belloni return -EINVAL; 572018d959bSAlexandre Belloni } 573018d959bSAlexandre Belloni 574018d959bSAlexandre Belloni return rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_BSM, 575018d959bSAlexandre Belloni FIELD_PREP(RV3028_BACKUP_BSM, mode)); 576018d959bSAlexandre Belloni 577018d959bSAlexandre Belloni default: 578018d959bSAlexandre Belloni return -EINVAL; 579018d959bSAlexandre Belloni } 580018d959bSAlexandre Belloni 581018d959bSAlexandre Belloni return 0; 582018d959bSAlexandre Belloni } 583018d959bSAlexandre Belloni 584e6e7376cSAlexandre Belloni static int rv3028_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 585e6e7376cSAlexandre Belloni { 586e6e7376cSAlexandre Belloni struct rv3028_data *rv3028 = dev_get_drvdata(dev); 587e6e7376cSAlexandre Belloni int status, ret = 0; 588e6e7376cSAlexandre Belloni 589e6e7376cSAlexandre Belloni switch (cmd) { 590e6e7376cSAlexandre Belloni case RTC_VL_READ: 591e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status); 592e6e7376cSAlexandre Belloni if (ret < 0) 593e6e7376cSAlexandre Belloni return ret; 594e6e7376cSAlexandre Belloni 59586e655f9SAlexandre Belloni status = status & RV3028_STATUS_PORF ? RTC_VL_DATA_INVALID : 0; 59686e655f9SAlexandre Belloni return put_user(status, (unsigned int __user *)arg); 597e6e7376cSAlexandre Belloni 598e6e7376cSAlexandre Belloni default: 599e6e7376cSAlexandre Belloni return -ENOIOCTLCMD; 600e6e7376cSAlexandre Belloni } 601e6e7376cSAlexandre Belloni } 602e6e7376cSAlexandre Belloni 603e6e7376cSAlexandre Belloni static int rv3028_nvram_write(void *priv, unsigned int offset, void *val, 604e6e7376cSAlexandre Belloni size_t bytes) 605e6e7376cSAlexandre Belloni { 606e6e7376cSAlexandre Belloni return regmap_bulk_write(priv, RV3028_RAM1 + offset, val, bytes); 607e6e7376cSAlexandre Belloni } 608e6e7376cSAlexandre Belloni 609e6e7376cSAlexandre Belloni static int rv3028_nvram_read(void *priv, unsigned int offset, void *val, 610e6e7376cSAlexandre Belloni size_t bytes) 611e6e7376cSAlexandre Belloni { 612e6e7376cSAlexandre Belloni return regmap_bulk_read(priv, RV3028_RAM1 + offset, val, bytes); 613e6e7376cSAlexandre Belloni } 614e6e7376cSAlexandre Belloni 615e6e7376cSAlexandre Belloni static int rv3028_eeprom_write(void *priv, unsigned int offset, void *val, 616e6e7376cSAlexandre Belloni size_t bytes) 617e6e7376cSAlexandre Belloni { 618de0ad60eSAlexandre Belloni struct rv3028_data *rv3028 = priv; 619de0ad60eSAlexandre Belloni u32 status, eerd; 620de0ad60eSAlexandre Belloni int i, ret; 621e6e7376cSAlexandre Belloni u8 *buf = val; 622e6e7376cSAlexandre Belloni 623de0ad60eSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd); 624e6e7376cSAlexandre Belloni if (ret) 625e6e7376cSAlexandre Belloni return ret; 626e6e7376cSAlexandre Belloni 627e6e7376cSAlexandre Belloni for (i = 0; i < bytes; i++) { 628de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i); 629e6e7376cSAlexandre Belloni if (ret) 630e6e7376cSAlexandre Belloni goto restore_eerd; 631e6e7376cSAlexandre Belloni 632de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_DATA, buf[i]); 633e6e7376cSAlexandre Belloni if (ret) 634e6e7376cSAlexandre Belloni goto restore_eerd; 635e6e7376cSAlexandre Belloni 636de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0); 637e6e7376cSAlexandre Belloni if (ret) 638e6e7376cSAlexandre Belloni goto restore_eerd; 639e6e7376cSAlexandre Belloni 640de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 641e6e7376cSAlexandre Belloni RV3028_EEPROM_CMD_WRITE); 642e6e7376cSAlexandre Belloni if (ret) 643e6e7376cSAlexandre Belloni goto restore_eerd; 644e6e7376cSAlexandre Belloni 645e6e7376cSAlexandre Belloni usleep_range(RV3028_EEBUSY_POLL, RV3028_EEBUSY_TIMEOUT); 646e6e7376cSAlexandre Belloni 647de0ad60eSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, 648e6e7376cSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY), 649e6e7376cSAlexandre Belloni RV3028_EEBUSY_POLL, 650e6e7376cSAlexandre Belloni RV3028_EEBUSY_TIMEOUT); 651e6e7376cSAlexandre Belloni if (ret) 652e6e7376cSAlexandre Belloni goto restore_eerd; 653e6e7376cSAlexandre Belloni } 654e6e7376cSAlexandre Belloni 655e6e7376cSAlexandre Belloni restore_eerd: 656de0ad60eSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd); 657e6e7376cSAlexandre Belloni 658e6e7376cSAlexandre Belloni return ret; 659e6e7376cSAlexandre Belloni } 660e6e7376cSAlexandre Belloni 661e6e7376cSAlexandre Belloni static int rv3028_eeprom_read(void *priv, unsigned int offset, void *val, 662e6e7376cSAlexandre Belloni size_t bytes) 663e6e7376cSAlexandre Belloni { 664de0ad60eSAlexandre Belloni struct rv3028_data *rv3028 = priv; 665de0ad60eSAlexandre Belloni u32 status, eerd, data; 666de0ad60eSAlexandre Belloni int i, ret; 667e6e7376cSAlexandre Belloni u8 *buf = val; 668e6e7376cSAlexandre Belloni 669de0ad60eSAlexandre Belloni ret = rv3028_enter_eerd(rv3028, &eerd); 670e6e7376cSAlexandre Belloni if (ret) 671e6e7376cSAlexandre Belloni return ret; 672e6e7376cSAlexandre Belloni 673e6e7376cSAlexandre Belloni for (i = 0; i < bytes; i++) { 674de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_ADDR, offset + i); 675e6e7376cSAlexandre Belloni if (ret) 676e6e7376cSAlexandre Belloni goto restore_eerd; 677e6e7376cSAlexandre Belloni 678de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 0x0); 679e6e7376cSAlexandre Belloni if (ret) 680e6e7376cSAlexandre Belloni goto restore_eerd; 681e6e7376cSAlexandre Belloni 682de0ad60eSAlexandre Belloni ret = regmap_write(rv3028->regmap, RV3028_EEPROM_CMD, 683e6e7376cSAlexandre Belloni RV3028_EEPROM_CMD_READ); 684e6e7376cSAlexandre Belloni if (ret) 685e6e7376cSAlexandre Belloni goto restore_eerd; 686e6e7376cSAlexandre Belloni 687de0ad60eSAlexandre Belloni ret = regmap_read_poll_timeout(rv3028->regmap, RV3028_STATUS, status, 688e6e7376cSAlexandre Belloni !(status & RV3028_STATUS_EEBUSY), 689e6e7376cSAlexandre Belloni RV3028_EEBUSY_POLL, 690e6e7376cSAlexandre Belloni RV3028_EEBUSY_TIMEOUT); 691e6e7376cSAlexandre Belloni if (ret) 692e6e7376cSAlexandre Belloni goto restore_eerd; 693e6e7376cSAlexandre Belloni 694de0ad60eSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_EEPROM_DATA, &data); 695e6e7376cSAlexandre Belloni if (ret) 696e6e7376cSAlexandre Belloni goto restore_eerd; 697e6e7376cSAlexandre Belloni buf[i] = data; 698e6e7376cSAlexandre Belloni } 699e6e7376cSAlexandre Belloni 700e6e7376cSAlexandre Belloni restore_eerd: 701de0ad60eSAlexandre Belloni rv3028_exit_eerd(rv3028, eerd); 702e6e7376cSAlexandre Belloni 703e6e7376cSAlexandre Belloni return ret; 704e6e7376cSAlexandre Belloni } 705e6e7376cSAlexandre Belloni 706f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK 707f583c341SParthiban Nallathambi #define clkout_hw_to_rv3028(hw) container_of(hw, struct rv3028_data, clkout_hw) 708f583c341SParthiban Nallathambi 709f583c341SParthiban Nallathambi static int clkout_rates[] = { 710f583c341SParthiban Nallathambi 32768, 711f583c341SParthiban Nallathambi 8192, 712f583c341SParthiban Nallathambi 1024, 713f583c341SParthiban Nallathambi 64, 714f583c341SParthiban Nallathambi 32, 715f583c341SParthiban Nallathambi 1, 716f583c341SParthiban Nallathambi }; 717f583c341SParthiban Nallathambi 718f583c341SParthiban Nallathambi static unsigned long rv3028_clkout_recalc_rate(struct clk_hw *hw, 719f583c341SParthiban Nallathambi unsigned long parent_rate) 720f583c341SParthiban Nallathambi { 721f583c341SParthiban Nallathambi int clkout, ret; 722f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); 723f583c341SParthiban Nallathambi 724f583c341SParthiban Nallathambi ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout); 725f583c341SParthiban Nallathambi if (ret < 0) 726f583c341SParthiban Nallathambi return 0; 727f583c341SParthiban Nallathambi 728f583c341SParthiban Nallathambi clkout &= RV3028_CLKOUT_FD_MASK; 729f583c341SParthiban Nallathambi return clkout_rates[clkout]; 730f583c341SParthiban Nallathambi } 731f583c341SParthiban Nallathambi 732f583c341SParthiban Nallathambi static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate, 733f583c341SParthiban Nallathambi unsigned long *prate) 734f583c341SParthiban Nallathambi { 735f583c341SParthiban Nallathambi int i; 736f583c341SParthiban Nallathambi 737f583c341SParthiban Nallathambi for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) 738f583c341SParthiban Nallathambi if (clkout_rates[i] <= rate) 739f583c341SParthiban Nallathambi return clkout_rates[i]; 740f583c341SParthiban Nallathambi 741f583c341SParthiban Nallathambi return 0; 742f583c341SParthiban Nallathambi } 743f583c341SParthiban Nallathambi 744f583c341SParthiban Nallathambi static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate, 745f583c341SParthiban Nallathambi unsigned long parent_rate) 746f583c341SParthiban Nallathambi { 747f583c341SParthiban Nallathambi int i, ret; 74800e8e87fSAlexandre Belloni u32 enabled; 749f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); 750f583c341SParthiban Nallathambi 75100e8e87fSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &enabled); 75200e8e87fSAlexandre Belloni if (ret < 0) 75300e8e87fSAlexandre Belloni return ret; 75400e8e87fSAlexandre Belloni 755f583c341SParthiban Nallathambi ret = regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0); 756f583c341SParthiban Nallathambi if (ret < 0) 757f583c341SParthiban Nallathambi return ret; 758f583c341SParthiban Nallathambi 75900e8e87fSAlexandre Belloni enabled &= RV3028_CLKOUT_CLKOE; 760f583c341SParthiban Nallathambi 76100e8e87fSAlexandre Belloni for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) 76200e8e87fSAlexandre Belloni if (clkout_rates[i] == rate) 763024e6f3dSAlexandre Belloni return rv3028_update_cfg(rv3028, RV3028_CLKOUT, 0xff, 76400e8e87fSAlexandre Belloni RV3028_CLKOUT_CLKSY | enabled | i); 765f583c341SParthiban Nallathambi 766f583c341SParthiban Nallathambi return -EINVAL; 767f583c341SParthiban Nallathambi } 768f583c341SParthiban Nallathambi 769f583c341SParthiban Nallathambi static int rv3028_clkout_prepare(struct clk_hw *hw) 770f583c341SParthiban Nallathambi { 771f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); 772f583c341SParthiban Nallathambi 773f583c341SParthiban Nallathambi return regmap_write(rv3028->regmap, RV3028_CLKOUT, 774f583c341SParthiban Nallathambi RV3028_CLKOUT_CLKSY | RV3028_CLKOUT_CLKOE); 775f583c341SParthiban Nallathambi } 776f583c341SParthiban Nallathambi 777f583c341SParthiban Nallathambi static void rv3028_clkout_unprepare(struct clk_hw *hw) 778f583c341SParthiban Nallathambi { 779f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); 780f583c341SParthiban Nallathambi 781f583c341SParthiban Nallathambi regmap_write(rv3028->regmap, RV3028_CLKOUT, 0x0); 782f583c341SParthiban Nallathambi regmap_update_bits(rv3028->regmap, RV3028_STATUS, 783f583c341SParthiban Nallathambi RV3028_STATUS_CLKF, 0); 784f583c341SParthiban Nallathambi } 785f583c341SParthiban Nallathambi 786f583c341SParthiban Nallathambi static int rv3028_clkout_is_prepared(struct clk_hw *hw) 787f583c341SParthiban Nallathambi { 788f583c341SParthiban Nallathambi int clkout, ret; 789f583c341SParthiban Nallathambi struct rv3028_data *rv3028 = clkout_hw_to_rv3028(hw); 790f583c341SParthiban Nallathambi 791f583c341SParthiban Nallathambi ret = regmap_read(rv3028->regmap, RV3028_CLKOUT, &clkout); 792f583c341SParthiban Nallathambi if (ret < 0) 793f583c341SParthiban Nallathambi return ret; 794f583c341SParthiban Nallathambi 795f583c341SParthiban Nallathambi return !!(clkout & RV3028_CLKOUT_CLKOE); 796f583c341SParthiban Nallathambi } 797f583c341SParthiban Nallathambi 798f583c341SParthiban Nallathambi static const struct clk_ops rv3028_clkout_ops = { 799f583c341SParthiban Nallathambi .prepare = rv3028_clkout_prepare, 800f583c341SParthiban Nallathambi .unprepare = rv3028_clkout_unprepare, 801f583c341SParthiban Nallathambi .is_prepared = rv3028_clkout_is_prepared, 802f583c341SParthiban Nallathambi .recalc_rate = rv3028_clkout_recalc_rate, 803f583c341SParthiban Nallathambi .round_rate = rv3028_clkout_round_rate, 804f583c341SParthiban Nallathambi .set_rate = rv3028_clkout_set_rate, 805f583c341SParthiban Nallathambi }; 806f583c341SParthiban Nallathambi 807f583c341SParthiban Nallathambi static int rv3028_clkout_register_clk(struct rv3028_data *rv3028, 808f583c341SParthiban Nallathambi struct i2c_client *client) 809f583c341SParthiban Nallathambi { 810f583c341SParthiban Nallathambi int ret; 811f583c341SParthiban Nallathambi struct clk *clk; 812f583c341SParthiban Nallathambi struct clk_init_data init; 813f583c341SParthiban Nallathambi struct device_node *node = client->dev.of_node; 814f583c341SParthiban Nallathambi 815f583c341SParthiban Nallathambi ret = regmap_update_bits(rv3028->regmap, RV3028_STATUS, 816f583c341SParthiban Nallathambi RV3028_STATUS_CLKF, 0); 817f583c341SParthiban Nallathambi if (ret < 0) 818f583c341SParthiban Nallathambi return ret; 819f583c341SParthiban Nallathambi 820f583c341SParthiban Nallathambi init.name = "rv3028-clkout"; 821f583c341SParthiban Nallathambi init.ops = &rv3028_clkout_ops; 822f583c341SParthiban Nallathambi init.flags = 0; 823f583c341SParthiban Nallathambi init.parent_names = NULL; 824f583c341SParthiban Nallathambi init.num_parents = 0; 825f583c341SParthiban Nallathambi rv3028->clkout_hw.init = &init; 826f583c341SParthiban Nallathambi 827f583c341SParthiban Nallathambi /* optional override of the clockname */ 828f583c341SParthiban Nallathambi of_property_read_string(node, "clock-output-names", &init.name); 829f583c341SParthiban Nallathambi 830f583c341SParthiban Nallathambi /* register the clock */ 831f583c341SParthiban Nallathambi clk = devm_clk_register(&client->dev, &rv3028->clkout_hw); 832f583c341SParthiban Nallathambi if (!IS_ERR(clk)) 833f583c341SParthiban Nallathambi of_clk_add_provider(node, of_clk_src_simple_get, clk); 834f583c341SParthiban Nallathambi 835f583c341SParthiban Nallathambi return 0; 836f583c341SParthiban Nallathambi } 837f583c341SParthiban Nallathambi #endif 838f583c341SParthiban Nallathambi 8390f769569SAlexandre Belloni static const struct rtc_class_ops rv3028_rtc_ops = { 840e6e7376cSAlexandre Belloni .read_time = rv3028_get_time, 841e6e7376cSAlexandre Belloni .set_time = rv3028_set_time, 8420f769569SAlexandre Belloni .read_alarm = rv3028_get_alarm, 8430f769569SAlexandre Belloni .set_alarm = rv3028_set_alarm, 8440f769569SAlexandre Belloni .alarm_irq_enable = rv3028_alarm_irq_enable, 845e6e7376cSAlexandre Belloni .read_offset = rv3028_read_offset, 846e6e7376cSAlexandre Belloni .set_offset = rv3028_set_offset, 847e6e7376cSAlexandre Belloni .ioctl = rv3028_ioctl, 848018d959bSAlexandre Belloni .param_get = rv3028_param_get, 849018d959bSAlexandre Belloni .param_set = rv3028_param_set, 850e6e7376cSAlexandre Belloni }; 851e6e7376cSAlexandre Belloni 852e6e7376cSAlexandre Belloni static const struct regmap_config regmap_config = { 853e6e7376cSAlexandre Belloni .reg_bits = 8, 854e6e7376cSAlexandre Belloni .val_bits = 8, 855e6e7376cSAlexandre Belloni .max_register = 0x37, 856e6e7376cSAlexandre Belloni }; 857e6e7376cSAlexandre Belloni 8583c87b351SAndrej Picej static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028, 8593c87b351SAndrej Picej struct i2c_client *client) 8603c87b351SAndrej Picej { 8613c87b351SAndrej Picej int ret, val_old, val; 8623c87b351SAndrej Picej u32 ohms, chargeable; 8633c87b351SAndrej Picej 8643c87b351SAndrej Picej ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old); 8653c87b351SAndrej Picej if (ret < 0) 8663c87b351SAndrej Picej return ret; 8673c87b351SAndrej Picej 8683c87b351SAndrej Picej /* mask out only trickle charger bits */ 8693c87b351SAndrej Picej val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK); 8703c87b351SAndrej Picej val = val_old; 8713c87b351SAndrej Picej 8723c87b351SAndrej Picej /* setup trickle charger */ 8733c87b351SAndrej Picej if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", 8743c87b351SAndrej Picej &ohms)) { 8753c87b351SAndrej Picej int i; 8763c87b351SAndrej Picej 8773c87b351SAndrej Picej for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++) 8783c87b351SAndrej Picej if (ohms == rv3028_trickle_resistors[i]) 8793c87b351SAndrej Picej break; 8803c87b351SAndrej Picej 8813c87b351SAndrej Picej if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { 8823c87b351SAndrej Picej /* enable trickle charger and its resistor */ 8833c87b351SAndrej Picej val = RV3028_BACKUP_TCE | i; 8843c87b351SAndrej Picej } else { 8853c87b351SAndrej Picej dev_warn(&client->dev, "invalid trickle resistor value\n"); 8863c87b351SAndrej Picej } 8873c87b351SAndrej Picej } 8883c87b351SAndrej Picej 8893c87b351SAndrej Picej if (!device_property_read_u32(&client->dev, "aux-voltage-chargeable", 8903c87b351SAndrej Picej &chargeable)) { 8913c87b351SAndrej Picej switch (chargeable) { 8923c87b351SAndrej Picej case 0: 8933c87b351SAndrej Picej val &= ~RV3028_BACKUP_TCE; 8943c87b351SAndrej Picej break; 8953c87b351SAndrej Picej case 1: 8963c87b351SAndrej Picej val |= RV3028_BACKUP_TCE; 8973c87b351SAndrej Picej break; 8983c87b351SAndrej Picej default: 8993c87b351SAndrej Picej dev_warn(&client->dev, 9003c87b351SAndrej Picej "unsupported aux-voltage-chargeable value\n"); 9013c87b351SAndrej Picej break; 9023c87b351SAndrej Picej } 9033c87b351SAndrej Picej } 9043c87b351SAndrej Picej 9053c87b351SAndrej Picej /* only update EEPROM if changes are necessary */ 9063c87b351SAndrej Picej if (val_old != val) { 9073c87b351SAndrej Picej ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | 9083c87b351SAndrej Picej RV3028_BACKUP_TCR_MASK, val); 9093c87b351SAndrej Picej if (ret) 9103c87b351SAndrej Picej return ret; 9113c87b351SAndrej Picej } 9123c87b351SAndrej Picej 9133c87b351SAndrej Picej return ret; 9143c87b351SAndrej Picej } 9153c87b351SAndrej Picej 916e6e7376cSAlexandre Belloni static int rv3028_probe(struct i2c_client *client) 917e6e7376cSAlexandre Belloni { 918e6e7376cSAlexandre Belloni struct rv3028_data *rv3028; 919e6e7376cSAlexandre Belloni int ret, status; 920e6e7376cSAlexandre Belloni struct nvmem_config nvmem_cfg = { 921e6e7376cSAlexandre Belloni .name = "rv3028_nvram", 922e6e7376cSAlexandre Belloni .word_size = 1, 923e6e7376cSAlexandre Belloni .stride = 1, 924e6e7376cSAlexandre Belloni .size = 2, 925e6e7376cSAlexandre Belloni .type = NVMEM_TYPE_BATTERY_BACKED, 926e6e7376cSAlexandre Belloni .reg_read = rv3028_nvram_read, 927e6e7376cSAlexandre Belloni .reg_write = rv3028_nvram_write, 928e6e7376cSAlexandre Belloni }; 929e6e7376cSAlexandre Belloni struct nvmem_config eeprom_cfg = { 930e6e7376cSAlexandre Belloni .name = "rv3028_eeprom", 931e6e7376cSAlexandre Belloni .word_size = 1, 932e6e7376cSAlexandre Belloni .stride = 1, 933e6e7376cSAlexandre Belloni .size = 43, 934e6e7376cSAlexandre Belloni .type = NVMEM_TYPE_EEPROM, 935e6e7376cSAlexandre Belloni .reg_read = rv3028_eeprom_read, 936e6e7376cSAlexandre Belloni .reg_write = rv3028_eeprom_write, 937e6e7376cSAlexandre Belloni }; 938e6e7376cSAlexandre Belloni 939e6e7376cSAlexandre Belloni rv3028 = devm_kzalloc(&client->dev, sizeof(struct rv3028_data), 940e6e7376cSAlexandre Belloni GFP_KERNEL); 941e6e7376cSAlexandre Belloni if (!rv3028) 942e6e7376cSAlexandre Belloni return -ENOMEM; 943e6e7376cSAlexandre Belloni 944e6e7376cSAlexandre Belloni rv3028->regmap = devm_regmap_init_i2c(client, ®map_config); 945c3b29bf6SChuhong Yuan if (IS_ERR(rv3028->regmap)) 946c3b29bf6SChuhong Yuan return PTR_ERR(rv3028->regmap); 947e6e7376cSAlexandre Belloni 948e6e7376cSAlexandre Belloni i2c_set_clientdata(client, rv3028); 949e6e7376cSAlexandre Belloni 950e6e7376cSAlexandre Belloni ret = regmap_read(rv3028->regmap, RV3028_STATUS, &status); 951e6e7376cSAlexandre Belloni if (ret < 0) 952e6e7376cSAlexandre Belloni return ret; 953e6e7376cSAlexandre Belloni 954e6e7376cSAlexandre Belloni if (status & RV3028_STATUS_AF) 955e6e7376cSAlexandre Belloni dev_warn(&client->dev, "An alarm may have been missed.\n"); 956e6e7376cSAlexandre Belloni 957e6e7376cSAlexandre Belloni rv3028->rtc = devm_rtc_allocate_device(&client->dev); 95844c638ceSAlexandre Belloni if (IS_ERR(rv3028->rtc)) 959e6e7376cSAlexandre Belloni return PTR_ERR(rv3028->rtc); 960e6e7376cSAlexandre Belloni 961e6e7376cSAlexandre Belloni if (client->irq > 0) { 96216b26f60SWadim Egorov unsigned long flags; 96316b26f60SWadim Egorov 96416b26f60SWadim Egorov /* 96516b26f60SWadim Egorov * If flags = 0, devm_request_threaded_irq() will use IRQ flags 96616b26f60SWadim Egorov * obtained from device tree. 96716b26f60SWadim Egorov */ 96816b26f60SWadim Egorov if (dev_fwnode(&client->dev)) 96916b26f60SWadim Egorov flags = 0; 97016b26f60SWadim Egorov else 97116b26f60SWadim Egorov flags = IRQF_TRIGGER_LOW; 97216b26f60SWadim Egorov 973e6e7376cSAlexandre Belloni ret = devm_request_threaded_irq(&client->dev, client->irq, 974e6e7376cSAlexandre Belloni NULL, rv3028_handle_irq, 97516b26f60SWadim Egorov flags | IRQF_ONESHOT, 976e6e7376cSAlexandre Belloni "rv3028", rv3028); 977e6e7376cSAlexandre Belloni if (ret) { 978e6e7376cSAlexandre Belloni dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); 979e6e7376cSAlexandre Belloni client->irq = 0; 980e6e7376cSAlexandre Belloni } 981e6e7376cSAlexandre Belloni } 9820f769569SAlexandre Belloni if (!client->irq) 9830f769569SAlexandre Belloni clear_bit(RTC_FEATURE_ALARM, rv3028->rtc->features); 984e6e7376cSAlexandre Belloni 985e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL1, 986e6e7376cSAlexandre Belloni RV3028_CTRL1_WADA, RV3028_CTRL1_WADA); 987e6e7376cSAlexandre Belloni if (ret) 988e6e7376cSAlexandre Belloni return ret; 989e6e7376cSAlexandre Belloni 990e6e7376cSAlexandre Belloni /* setup timestamping */ 991e6e7376cSAlexandre Belloni ret = regmap_update_bits(rv3028->regmap, RV3028_CTRL2, 992e6e7376cSAlexandre Belloni RV3028_CTRL2_EIE | RV3028_CTRL2_TSE, 993e6e7376cSAlexandre Belloni RV3028_CTRL2_EIE | RV3028_CTRL2_TSE); 994e6e7376cSAlexandre Belloni if (ret) 995e6e7376cSAlexandre Belloni return ret; 996e6e7376cSAlexandre Belloni 9973c87b351SAndrej Picej ret = rv3028_set_trickle_charger(rv3028, client); 998e6e7376cSAlexandre Belloni if (ret) 999e6e7376cSAlexandre Belloni return ret; 1000e6e7376cSAlexandre Belloni 1001e6e7376cSAlexandre Belloni ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group); 1002e6e7376cSAlexandre Belloni if (ret) 1003e6e7376cSAlexandre Belloni return ret; 1004e6e7376cSAlexandre Belloni 1005018d959bSAlexandre Belloni set_bit(RTC_FEATURE_BACKUP_SWITCH_MODE, rv3028->rtc->features); 1006018d959bSAlexandre Belloni 1007e6e7376cSAlexandre Belloni rv3028->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 1008e6e7376cSAlexandre Belloni rv3028->rtc->range_max = RTC_TIMESTAMP_END_2099; 1009e6e7376cSAlexandre Belloni rv3028->rtc->ops = &rv3028_rtc_ops; 1010fdcfd854SBartosz Golaszewski ret = devm_rtc_register_device(rv3028->rtc); 1011e6e7376cSAlexandre Belloni if (ret) 1012e6e7376cSAlexandre Belloni return ret; 1013e6e7376cSAlexandre Belloni 1014e6e7376cSAlexandre Belloni nvmem_cfg.priv = rv3028->regmap; 10153a905c2dSBartosz Golaszewski devm_rtc_nvmem_register(rv3028->rtc, &nvmem_cfg); 1016de0ad60eSAlexandre Belloni eeprom_cfg.priv = rv3028; 10173a905c2dSBartosz Golaszewski devm_rtc_nvmem_register(rv3028->rtc, &eeprom_cfg); 1018e6e7376cSAlexandre Belloni 1019e6e7376cSAlexandre Belloni rv3028->rtc->max_user_freq = 1; 1020e6e7376cSAlexandre Belloni 1021f583c341SParthiban Nallathambi #ifdef CONFIG_COMMON_CLK 1022f583c341SParthiban Nallathambi rv3028_clkout_register_clk(rv3028, client); 1023f583c341SParthiban Nallathambi #endif 1024e6e7376cSAlexandre Belloni return 0; 1025e6e7376cSAlexandre Belloni } 1026e6e7376cSAlexandre Belloni 1027b6ef5d4aSAlexandre Belloni static const struct acpi_device_id rv3028_i2c_acpi_match[] = { 1028b6ef5d4aSAlexandre Belloni { "MCRY3028" }, 1029b6ef5d4aSAlexandre Belloni { } 1030b6ef5d4aSAlexandre Belloni }; 1031b6ef5d4aSAlexandre Belloni MODULE_DEVICE_TABLE(acpi, rv3028_i2c_acpi_match); 1032b6ef5d4aSAlexandre Belloni 1033dff31b0bSAlexandre Belloni static const __maybe_unused struct of_device_id rv3028_of_match[] = { 1034e6e7376cSAlexandre Belloni { .compatible = "microcrystal,rv3028", }, 1035e6e7376cSAlexandre Belloni { } 1036e6e7376cSAlexandre Belloni }; 1037e6e7376cSAlexandre Belloni MODULE_DEVICE_TABLE(of, rv3028_of_match); 1038e6e7376cSAlexandre Belloni 10397e2a60efSJohannes Kirchmair static const struct i2c_device_id rv3028_id_table[] = { 10407e2a60efSJohannes Kirchmair { .name = "rv3028", }, 10417e2a60efSJohannes Kirchmair { } 10427e2a60efSJohannes Kirchmair }; 10437e2a60efSJohannes Kirchmair MODULE_DEVICE_TABLE(i2c, rv3028_id_table); 10447e2a60efSJohannes Kirchmair 1045e6e7376cSAlexandre Belloni static struct i2c_driver rv3028_driver = { 1046e6e7376cSAlexandre Belloni .driver = { 1047e6e7376cSAlexandre Belloni .name = "rtc-rv3028", 1048b6ef5d4aSAlexandre Belloni .acpi_match_table = rv3028_i2c_acpi_match, 1049e6e7376cSAlexandre Belloni .of_match_table = of_match_ptr(rv3028_of_match), 1050e6e7376cSAlexandre Belloni }, 10517e2a60efSJohannes Kirchmair .id_table = rv3028_id_table, 105231b0cecbSUwe Kleine-König .probe = rv3028_probe, 1053e6e7376cSAlexandre Belloni }; 1054e6e7376cSAlexandre Belloni module_i2c_driver(rv3028_driver); 1055e6e7376cSAlexandre Belloni 1056e6e7376cSAlexandre Belloni MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>"); 1057e6e7376cSAlexandre Belloni MODULE_DESCRIPTION("Micro Crystal RV3028 RTC driver"); 1058e6e7376cSAlexandre Belloni MODULE_LICENSE("GPL v2"); 1059