18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Real Time Clock driver for AB-RTCMC-32.768kHz-EOZ9 chip. 48c2ecf20Sopenharmony_ci * Copyright (C) 2019 Orolia 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/rtc.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/bcd.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/regmap.h> 148c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 158c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1 0x00 188c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_MASK GENMASK(7, 0) 198c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_WE BIT(0) 208c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_TE BIT(1) 218c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_TAR BIT(2) 228c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_EERE BIT(3) 238c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_SRON BIT(4) 248c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_TD0 BIT(5) 258c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_TD1 BIT(6) 268c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL1_CLKINT BIT(7) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT 0x01 298c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_AIE BIT(0) 308c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_TIE BIT(1) 318c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_V1IE BIT(2) 328c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_V2IE BIT(3) 338c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_SRIE BIT(4) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_FLAG 0x02 368c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_FLAG_AF BIT(0) 378c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_FLAG_TF BIT(1) 388c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_FLAG_V1IF BIT(2) 398c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_FLAG_V2IF BIT(3) 408c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_INT_FLAG_SRF BIT(4) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_STATUS 0x03 438c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_STATUS_V1F BIT(2) 448c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_STATUS_V2F BIT(3) 458c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_STATUS_SR BIT(4) 468c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_STATUS_PON BIT(5) 478c2ecf20Sopenharmony_ci#define ABEOZ9_REG_CTRL_STATUS_EEBUSY BIT(7) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define ABEOZ9_REG_SEC 0x08 508c2ecf20Sopenharmony_ci#define ABEOZ9_REG_MIN 0x09 518c2ecf20Sopenharmony_ci#define ABEOZ9_REG_HOURS 0x0A 528c2ecf20Sopenharmony_ci#define ABEOZ9_HOURS_PM BIT(6) 538c2ecf20Sopenharmony_ci#define ABEOZ9_REG_DAYS 0x0B 548c2ecf20Sopenharmony_ci#define ABEOZ9_REG_WEEKDAYS 0x0C 558c2ecf20Sopenharmony_ci#define ABEOZ9_REG_MONTHS 0x0D 568c2ecf20Sopenharmony_ci#define ABEOZ9_REG_YEARS 0x0E 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define ABEOZ9_SEC_LEN 7 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define ABEOZ9_REG_REG_TEMP 0x20 618c2ecf20Sopenharmony_ci#define ABEOZ953_TEMP_MAX 120 628c2ecf20Sopenharmony_ci#define ABEOZ953_TEMP_MIN -60 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM 0x30 658c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_MASK GENMASK(8, 0) 668c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_THP BIT(0) 678c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_THE BIT(1) 688c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_FD0 BIT(2) 698c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_FD1 BIT(3) 708c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_R1K BIT(4) 718c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_R5K BIT(5) 728c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_R20K BIT(6) 738c2ecf20Sopenharmony_ci#define ABEOZ9_REG_EEPROM_R80K BIT(7) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct abeoz9_rtc_data { 768c2ecf20Sopenharmony_ci struct rtc_device *rtc; 778c2ecf20Sopenharmony_ci struct regmap *regmap; 788c2ecf20Sopenharmony_ci struct device *hwmon_dev; 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int abeoz9_check_validity(struct device *dev) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data = dev_get_drvdata(dev); 848c2ecf20Sopenharmony_ci struct regmap *regmap = data->regmap; 858c2ecf20Sopenharmony_ci int ret; 868c2ecf20Sopenharmony_ci int val; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci ret = regmap_read(regmap, ABEOZ9_REG_CTRL_STATUS, &val); 898c2ecf20Sopenharmony_ci if (ret < 0) { 908c2ecf20Sopenharmony_ci dev_err(dev, 918c2ecf20Sopenharmony_ci "unable to get CTRL_STATUS register (%d)\n", ret); 928c2ecf20Sopenharmony_ci return ret; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (val & ABEOZ9_REG_CTRL_STATUS_PON) { 968c2ecf20Sopenharmony_ci dev_warn(dev, "power-on reset detected, date is invalid\n"); 978c2ecf20Sopenharmony_ci return -EINVAL; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (val & ABEOZ9_REG_CTRL_STATUS_V1F) { 1018c2ecf20Sopenharmony_ci dev_warn(dev, 1028c2ecf20Sopenharmony_ci "voltage drops below VLOW1 threshold, date is invalid\n"); 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if ((val & ABEOZ9_REG_CTRL_STATUS_V2F)) { 1078c2ecf20Sopenharmony_ci dev_warn(dev, 1088c2ecf20Sopenharmony_ci "voltage drops below VLOW2 threshold, date is invalid\n"); 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int abeoz9_reset_validity(struct regmap *regmap) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return regmap_update_bits(regmap, ABEOZ9_REG_CTRL_STATUS, 1188c2ecf20Sopenharmony_ci ABEOZ9_REG_CTRL_STATUS_V1F | 1198c2ecf20Sopenharmony_ci ABEOZ9_REG_CTRL_STATUS_V2F | 1208c2ecf20Sopenharmony_ci ABEOZ9_REG_CTRL_STATUS_PON, 1218c2ecf20Sopenharmony_ci 0); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int abeoz9_rtc_get_time(struct device *dev, struct rtc_time *tm) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data = dev_get_drvdata(dev); 1278c2ecf20Sopenharmony_ci u8 regs[ABEOZ9_SEC_LEN]; 1288c2ecf20Sopenharmony_ci int ret; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci ret = abeoz9_check_validity(dev); 1318c2ecf20Sopenharmony_ci if (ret) 1328c2ecf20Sopenharmony_ci return ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ret = regmap_bulk_read(data->regmap, ABEOZ9_REG_SEC, 1358c2ecf20Sopenharmony_ci regs, 1368c2ecf20Sopenharmony_ci sizeof(regs)); 1378c2ecf20Sopenharmony_ci if (ret) { 1388c2ecf20Sopenharmony_ci dev_err(dev, "reading RTC time failed (%d)\n", ret); 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci tm->tm_sec = bcd2bin(regs[ABEOZ9_REG_SEC - ABEOZ9_REG_SEC] & 0x7F); 1438c2ecf20Sopenharmony_ci tm->tm_min = bcd2bin(regs[ABEOZ9_REG_MIN - ABEOZ9_REG_SEC] & 0x7F); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] & ABEOZ9_HOURS_PM) { 1468c2ecf20Sopenharmony_ci tm->tm_hour = 1478c2ecf20Sopenharmony_ci bcd2bin(regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] & 0x1f); 1488c2ecf20Sopenharmony_ci if (regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] & ABEOZ9_HOURS_PM) 1498c2ecf20Sopenharmony_ci tm->tm_hour += 12; 1508c2ecf20Sopenharmony_ci } else { 1518c2ecf20Sopenharmony_ci tm->tm_hour = bcd2bin(regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC]); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci tm->tm_mday = bcd2bin(regs[ABEOZ9_REG_DAYS - ABEOZ9_REG_SEC]); 1558c2ecf20Sopenharmony_ci tm->tm_wday = bcd2bin(regs[ABEOZ9_REG_WEEKDAYS - ABEOZ9_REG_SEC]); 1568c2ecf20Sopenharmony_ci tm->tm_mon = bcd2bin(regs[ABEOZ9_REG_MONTHS - ABEOZ9_REG_SEC]) - 1; 1578c2ecf20Sopenharmony_ci tm->tm_year = bcd2bin(regs[ABEOZ9_REG_YEARS - ABEOZ9_REG_SEC]) + 100; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int abeoz9_rtc_set_time(struct device *dev, struct rtc_time *tm) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data = dev_get_drvdata(dev); 1658c2ecf20Sopenharmony_ci struct regmap *regmap = data->regmap; 1668c2ecf20Sopenharmony_ci u8 regs[ABEOZ9_SEC_LEN]; 1678c2ecf20Sopenharmony_ci int ret; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci regs[ABEOZ9_REG_SEC - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_sec); 1708c2ecf20Sopenharmony_ci regs[ABEOZ9_REG_MIN - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_min); 1718c2ecf20Sopenharmony_ci regs[ABEOZ9_REG_HOURS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_hour); 1728c2ecf20Sopenharmony_ci regs[ABEOZ9_REG_DAYS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_mday); 1738c2ecf20Sopenharmony_ci regs[ABEOZ9_REG_WEEKDAYS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_wday); 1748c2ecf20Sopenharmony_ci regs[ABEOZ9_REG_MONTHS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_mon + 1); 1758c2ecf20Sopenharmony_ci regs[ABEOZ9_REG_YEARS - ABEOZ9_REG_SEC] = bin2bcd(tm->tm_year - 100); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ret = regmap_bulk_write(data->regmap, ABEOZ9_REG_SEC, 1788c2ecf20Sopenharmony_ci regs, 1798c2ecf20Sopenharmony_ci sizeof(regs)); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (ret) { 1828c2ecf20Sopenharmony_ci dev_err(dev, "set RTC time failed (%d)\n", ret); 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return abeoz9_reset_validity(regmap); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int abeoz9_trickle_parse_dt(struct device_node *node) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci u32 ohms = 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (of_property_read_u32(node, "trickle-resistor-ohms", &ohms)) 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci switch (ohms) { 1978c2ecf20Sopenharmony_ci case 1000: 1988c2ecf20Sopenharmony_ci return ABEOZ9_REG_EEPROM_R1K; 1998c2ecf20Sopenharmony_ci case 5000: 2008c2ecf20Sopenharmony_ci return ABEOZ9_REG_EEPROM_R5K; 2018c2ecf20Sopenharmony_ci case 20000: 2028c2ecf20Sopenharmony_ci return ABEOZ9_REG_EEPROM_R20K; 2038c2ecf20Sopenharmony_ci case 80000: 2048c2ecf20Sopenharmony_ci return ABEOZ9_REG_EEPROM_R80K; 2058c2ecf20Sopenharmony_ci default: 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int abeoz9_rtc_setup(struct device *dev, struct device_node *node) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data = dev_get_drvdata(dev); 2138c2ecf20Sopenharmony_ci struct regmap *regmap = data->regmap; 2148c2ecf20Sopenharmony_ci int ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* Enable Self Recovery, Clock for Watch and EEPROM refresh functions */ 2178c2ecf20Sopenharmony_ci ret = regmap_update_bits(regmap, ABEOZ9_REG_CTRL1, 2188c2ecf20Sopenharmony_ci ABEOZ9_REG_CTRL1_MASK, 2198c2ecf20Sopenharmony_ci ABEOZ9_REG_CTRL1_WE | 2208c2ecf20Sopenharmony_ci ABEOZ9_REG_CTRL1_EERE | 2218c2ecf20Sopenharmony_ci ABEOZ9_REG_CTRL1_SRON); 2228c2ecf20Sopenharmony_ci if (ret < 0) { 2238c2ecf20Sopenharmony_ci dev_err(dev, "unable to set CTRL_1 register (%d)\n", ret); 2248c2ecf20Sopenharmony_ci return ret; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ret = regmap_write(regmap, ABEOZ9_REG_CTRL_INT, 0); 2288c2ecf20Sopenharmony_ci if (ret < 0) { 2298c2ecf20Sopenharmony_ci dev_err(dev, 2308c2ecf20Sopenharmony_ci "unable to set control CTRL_INT register (%d)\n", 2318c2ecf20Sopenharmony_ci ret); 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ret = regmap_write(regmap, ABEOZ9_REG_CTRL_INT_FLAG, 0); 2368c2ecf20Sopenharmony_ci if (ret < 0) { 2378c2ecf20Sopenharmony_ci dev_err(dev, 2388c2ecf20Sopenharmony_ci "unable to set control CTRL_INT_FLAG register (%d)\n", 2398c2ecf20Sopenharmony_ci ret); 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci ret = abeoz9_trickle_parse_dt(node); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Enable built-in termometer */ 2468c2ecf20Sopenharmony_ci ret |= ABEOZ9_REG_EEPROM_THE; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci ret = regmap_update_bits(regmap, ABEOZ9_REG_EEPROM, 2498c2ecf20Sopenharmony_ci ABEOZ9_REG_EEPROM_MASK, 2508c2ecf20Sopenharmony_ci ret); 2518c2ecf20Sopenharmony_ci if (ret < 0) { 2528c2ecf20Sopenharmony_ci dev_err(dev, "unable to set EEPROM register (%d)\n", ret); 2538c2ecf20Sopenharmony_ci return ret; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic const struct rtc_class_ops rtc_ops = { 2608c2ecf20Sopenharmony_ci .read_time = abeoz9_rtc_get_time, 2618c2ecf20Sopenharmony_ci .set_time = abeoz9_rtc_set_time, 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic const struct regmap_config abeoz9_rtc_regmap_config = { 2658c2ecf20Sopenharmony_ci .reg_bits = 8, 2668c2ecf20Sopenharmony_ci .val_bits = 8, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci#if IS_REACHABLE(CONFIG_HWMON) 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int abeoz9z3_temp_read(struct device *dev, 2728c2ecf20Sopenharmony_ci enum hwmon_sensor_types type, 2738c2ecf20Sopenharmony_ci u32 attr, int channel, long *temp) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data = dev_get_drvdata(dev); 2768c2ecf20Sopenharmony_ci struct regmap *regmap = data->regmap; 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci unsigned int val; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = regmap_read(regmap, ABEOZ9_REG_CTRL_STATUS, &val); 2818c2ecf20Sopenharmony_ci if (ret < 0) 2828c2ecf20Sopenharmony_ci return ret; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if ((val & ABEOZ9_REG_CTRL_STATUS_V1F) || 2858c2ecf20Sopenharmony_ci (val & ABEOZ9_REG_CTRL_STATUS_V2F)) { 2868c2ecf20Sopenharmony_ci dev_err(dev, 2878c2ecf20Sopenharmony_ci "thermometer might be disabled due to low voltage\n"); 2888c2ecf20Sopenharmony_ci return -EINVAL; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci switch (attr) { 2928c2ecf20Sopenharmony_ci case hwmon_temp_input: 2938c2ecf20Sopenharmony_ci ret = regmap_read(regmap, ABEOZ9_REG_REG_TEMP, &val); 2948c2ecf20Sopenharmony_ci if (ret < 0) 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci *temp = 1000 * (val + ABEOZ953_TEMP_MIN); 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci case hwmon_temp_max: 2998c2ecf20Sopenharmony_ci *temp = 1000 * ABEOZ953_TEMP_MAX; 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci case hwmon_temp_min: 3028c2ecf20Sopenharmony_ci *temp = 1000 * ABEOZ953_TEMP_MIN; 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci default: 3058c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic umode_t abeoz9_is_visible(const void *data, 3108c2ecf20Sopenharmony_ci enum hwmon_sensor_types type, 3118c2ecf20Sopenharmony_ci u32 attr, int channel) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci switch (attr) { 3148c2ecf20Sopenharmony_ci case hwmon_temp_input: 3158c2ecf20Sopenharmony_ci case hwmon_temp_max: 3168c2ecf20Sopenharmony_ci case hwmon_temp_min: 3178c2ecf20Sopenharmony_ci return 0444; 3188c2ecf20Sopenharmony_ci default: 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic const u32 abeoz9_chip_config[] = { 3248c2ecf20Sopenharmony_ci HWMON_C_REGISTER_TZ, 3258c2ecf20Sopenharmony_ci 0 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info abeoz9_chip = { 3298c2ecf20Sopenharmony_ci .type = hwmon_chip, 3308c2ecf20Sopenharmony_ci .config = abeoz9_chip_config, 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic const u32 abeoz9_temp_config[] = { 3348c2ecf20Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN, 3358c2ecf20Sopenharmony_ci 0 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info abeoz9_temp = { 3398c2ecf20Sopenharmony_ci .type = hwmon_temp, 3408c2ecf20Sopenharmony_ci .config = abeoz9_temp_config, 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *abeoz9_info[] = { 3448c2ecf20Sopenharmony_ci &abeoz9_chip, 3458c2ecf20Sopenharmony_ci &abeoz9_temp, 3468c2ecf20Sopenharmony_ci NULL 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const struct hwmon_ops abeoz9_hwmon_ops = { 3508c2ecf20Sopenharmony_ci .is_visible = abeoz9_is_visible, 3518c2ecf20Sopenharmony_ci .read = abeoz9z3_temp_read, 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info abeoz9_chip_info = { 3558c2ecf20Sopenharmony_ci .ops = &abeoz9_hwmon_ops, 3568c2ecf20Sopenharmony_ci .info = abeoz9_info, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void abeoz9_hwmon_register(struct device *dev, 3608c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci data->hwmon_dev = 3638c2ecf20Sopenharmony_ci devm_hwmon_device_register_with_info(dev, 3648c2ecf20Sopenharmony_ci "abeoz9", 3658c2ecf20Sopenharmony_ci data, 3668c2ecf20Sopenharmony_ci &abeoz9_chip_info, 3678c2ecf20Sopenharmony_ci NULL); 3688c2ecf20Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 3698c2ecf20Sopenharmony_ci dev_warn(dev, "unable to register hwmon device %ld\n", 3708c2ecf20Sopenharmony_ci PTR_ERR(data->hwmon_dev)); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci#else 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void abeoz9_hwmon_register(struct device *dev, 3778c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci#endif 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int abeoz9_probe(struct i2c_client *client, 3848c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct abeoz9_rtc_data *data = NULL; 3878c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 3888c2ecf20Sopenharmony_ci struct regmap *regmap; 3898c2ecf20Sopenharmony_ci int ret; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | 3928c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE_DATA | 3938c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_I2C_BLOCK)) 3948c2ecf20Sopenharmony_ci return -ENODEV; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci regmap = devm_regmap_init_i2c(client, &abeoz9_rtc_regmap_config); 3978c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 3988c2ecf20Sopenharmony_ci ret = PTR_ERR(regmap); 3998c2ecf20Sopenharmony_ci dev_err(dev, "regmap allocation failed: %d\n", ret); 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 4048c2ecf20Sopenharmony_ci if (!data) 4058c2ecf20Sopenharmony_ci return -ENOMEM; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci data->regmap = regmap; 4088c2ecf20Sopenharmony_ci dev_set_drvdata(dev, data); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci ret = abeoz9_rtc_setup(dev, client->dev.of_node); 4118c2ecf20Sopenharmony_ci if (ret) 4128c2ecf20Sopenharmony_ci return ret; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci data->rtc = devm_rtc_allocate_device(dev); 4158c2ecf20Sopenharmony_ci ret = PTR_ERR_OR_ZERO(data->rtc); 4168c2ecf20Sopenharmony_ci if (ret) 4178c2ecf20Sopenharmony_ci return ret; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci data->rtc->ops = &rtc_ops; 4208c2ecf20Sopenharmony_ci data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 4218c2ecf20Sopenharmony_ci data->rtc->range_max = RTC_TIMESTAMP_END_2099; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci ret = rtc_register_device(data->rtc); 4248c2ecf20Sopenharmony_ci if (ret) 4258c2ecf20Sopenharmony_ci return ret; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci abeoz9_hwmon_register(dev, data); 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 4328c2ecf20Sopenharmony_cistatic const struct of_device_id abeoz9_dt_match[] = { 4338c2ecf20Sopenharmony_ci { .compatible = "abracon,abeoz9" }, 4348c2ecf20Sopenharmony_ci { }, 4358c2ecf20Sopenharmony_ci}; 4368c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, abeoz9_dt_match); 4378c2ecf20Sopenharmony_ci#endif 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic const struct i2c_device_id abeoz9_id[] = { 4408c2ecf20Sopenharmony_ci { "abeoz9", 0 }, 4418c2ecf20Sopenharmony_ci { } 4428c2ecf20Sopenharmony_ci}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic struct i2c_driver abeoz9_driver = { 4458c2ecf20Sopenharmony_ci .driver = { 4468c2ecf20Sopenharmony_ci .name = "rtc-ab-eoz9", 4478c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(abeoz9_dt_match), 4488c2ecf20Sopenharmony_ci }, 4498c2ecf20Sopenharmony_ci .probe = abeoz9_probe, 4508c2ecf20Sopenharmony_ci .id_table = abeoz9_id, 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cimodule_i2c_driver(abeoz9_driver); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Artem Panfilov <panfilov.artyom@gmail.com>"); 4568c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Abracon AB-RTCMC-32.768kHz-EOZ9 RTC driver"); 4578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 458