18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* rtc-ds1343.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible 58c2ecf20Sopenharmony_ci * Real Time Clock 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> 88c2ecf20Sopenharmony_ci * Ankur Srivastava <sankurece@gmail.com> : DS1343 Nvram Support 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 168c2ecf20Sopenharmony_ci#include <linux/regmap.h> 178c2ecf20Sopenharmony_ci#include <linux/rtc.h> 188c2ecf20Sopenharmony_ci#include <linux/bcd.h> 198c2ecf20Sopenharmony_ci#include <linux/pm.h> 208c2ecf20Sopenharmony_ci#include <linux/pm_wakeirq.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DALLAS_MAXIM_DS1343 0 248c2ecf20Sopenharmony_ci#define DALLAS_MAXIM_DS1344 1 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* RTC DS1343 Registers */ 278c2ecf20Sopenharmony_ci#define DS1343_SECONDS_REG 0x00 288c2ecf20Sopenharmony_ci#define DS1343_MINUTES_REG 0x01 298c2ecf20Sopenharmony_ci#define DS1343_HOURS_REG 0x02 308c2ecf20Sopenharmony_ci#define DS1343_DAY_REG 0x03 318c2ecf20Sopenharmony_ci#define DS1343_DATE_REG 0x04 328c2ecf20Sopenharmony_ci#define DS1343_MONTH_REG 0x05 338c2ecf20Sopenharmony_ci#define DS1343_YEAR_REG 0x06 348c2ecf20Sopenharmony_ci#define DS1343_ALM0_SEC_REG 0x07 358c2ecf20Sopenharmony_ci#define DS1343_ALM0_MIN_REG 0x08 368c2ecf20Sopenharmony_ci#define DS1343_ALM0_HOUR_REG 0x09 378c2ecf20Sopenharmony_ci#define DS1343_ALM0_DAY_REG 0x0A 388c2ecf20Sopenharmony_ci#define DS1343_ALM1_SEC_REG 0x0B 398c2ecf20Sopenharmony_ci#define DS1343_ALM1_MIN_REG 0x0C 408c2ecf20Sopenharmony_ci#define DS1343_ALM1_HOUR_REG 0x0D 418c2ecf20Sopenharmony_ci#define DS1343_ALM1_DAY_REG 0x0E 428c2ecf20Sopenharmony_ci#define DS1343_CONTROL_REG 0x0F 438c2ecf20Sopenharmony_ci#define DS1343_STATUS_REG 0x10 448c2ecf20Sopenharmony_ci#define DS1343_TRICKLE_REG 0x11 458c2ecf20Sopenharmony_ci#define DS1343_NVRAM 0x20 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define DS1343_NVRAM_LEN 96 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* DS1343 Control Registers bits */ 508c2ecf20Sopenharmony_ci#define DS1343_EOSC 0x80 518c2ecf20Sopenharmony_ci#define DS1343_DOSF 0x20 528c2ecf20Sopenharmony_ci#define DS1343_EGFIL 0x10 538c2ecf20Sopenharmony_ci#define DS1343_SQW 0x08 548c2ecf20Sopenharmony_ci#define DS1343_INTCN 0x04 558c2ecf20Sopenharmony_ci#define DS1343_A1IE 0x02 568c2ecf20Sopenharmony_ci#define DS1343_A0IE 0x01 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* DS1343 Status Registers bits */ 598c2ecf20Sopenharmony_ci#define DS1343_OSF 0x80 608c2ecf20Sopenharmony_ci#define DS1343_IRQF1 0x02 618c2ecf20Sopenharmony_ci#define DS1343_IRQF0 0x01 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* DS1343 Trickle Charger Registers bits */ 648c2ecf20Sopenharmony_ci#define DS1343_TRICKLE_MAGIC 0xa0 658c2ecf20Sopenharmony_ci#define DS1343_TRICKLE_DS1 0x08 668c2ecf20Sopenharmony_ci#define DS1343_TRICKLE_1K 0x01 678c2ecf20Sopenharmony_ci#define DS1343_TRICKLE_2K 0x02 688c2ecf20Sopenharmony_ci#define DS1343_TRICKLE_4K 0x03 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic const struct spi_device_id ds1343_id[] = { 718c2ecf20Sopenharmony_ci { "ds1343", DALLAS_MAXIM_DS1343 }, 728c2ecf20Sopenharmony_ci { "ds1344", DALLAS_MAXIM_DS1344 }, 738c2ecf20Sopenharmony_ci { } 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ds1343_id); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct ds1343_priv { 788c2ecf20Sopenharmony_ci struct rtc_device *rtc; 798c2ecf20Sopenharmony_ci struct regmap *map; 808c2ecf20Sopenharmony_ci int irq; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic ssize_t ds1343_show_glitchfilter(struct device *dev, 848c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev->parent); 878c2ecf20Sopenharmony_ci int glitch_filt_status, data; 888c2ecf20Sopenharmony_ci int res; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci res = regmap_read(priv->map, DS1343_CONTROL_REG, &data); 918c2ecf20Sopenharmony_ci if (res) 928c2ecf20Sopenharmony_ci return res; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci glitch_filt_status = !!(data & DS1343_EGFIL); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (glitch_filt_status) 978c2ecf20Sopenharmony_ci return sprintf(buf, "enabled\n"); 988c2ecf20Sopenharmony_ci else 998c2ecf20Sopenharmony_ci return sprintf(buf, "disabled\n"); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic ssize_t ds1343_store_glitchfilter(struct device *dev, 1038c2ecf20Sopenharmony_ci struct device_attribute *attr, 1048c2ecf20Sopenharmony_ci const char *buf, size_t count) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev->parent); 1078c2ecf20Sopenharmony_ci int data = 0; 1088c2ecf20Sopenharmony_ci int res; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (strncmp(buf, "enabled", 7) == 0) 1118c2ecf20Sopenharmony_ci data = DS1343_EGFIL; 1128c2ecf20Sopenharmony_ci else if (strncmp(buf, "disabled", 8)) 1138c2ecf20Sopenharmony_ci return -EINVAL; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci res = regmap_update_bits(priv->map, DS1343_CONTROL_REG, 1168c2ecf20Sopenharmony_ci DS1343_EGFIL, data); 1178c2ecf20Sopenharmony_ci if (res) 1188c2ecf20Sopenharmony_ci return res; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return count; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter, 1248c2ecf20Sopenharmony_ci ds1343_store_glitchfilter); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int ds1343_nvram_write(void *priv, unsigned int off, void *val, 1278c2ecf20Sopenharmony_ci size_t bytes) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct ds1343_priv *ds1343 = priv; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return regmap_bulk_write(ds1343->map, DS1343_NVRAM + off, val, bytes); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int ds1343_nvram_read(void *priv, unsigned int off, void *val, 1358c2ecf20Sopenharmony_ci size_t bytes) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct ds1343_priv *ds1343 = priv; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return regmap_bulk_read(ds1343->map, DS1343_NVRAM + off, val, bytes); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic ssize_t ds1343_show_tricklecharger(struct device *dev, 1438c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev->parent); 1468c2ecf20Sopenharmony_ci int res, data; 1478c2ecf20Sopenharmony_ci char *diodes = "disabled", *resistors = " "; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci res = regmap_read(priv->map, DS1343_TRICKLE_REG, &data); 1508c2ecf20Sopenharmony_ci if (res) 1518c2ecf20Sopenharmony_ci return res; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) { 1548c2ecf20Sopenharmony_ci switch (data & 0x0c) { 1558c2ecf20Sopenharmony_ci case DS1343_TRICKLE_DS1: 1568c2ecf20Sopenharmony_ci diodes = "one diode,"; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci default: 1608c2ecf20Sopenharmony_ci diodes = "no diode,"; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci switch (data & 0x03) { 1658c2ecf20Sopenharmony_ci case DS1343_TRICKLE_1K: 1668c2ecf20Sopenharmony_ci resistors = "1k Ohm"; 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci case DS1343_TRICKLE_2K: 1708c2ecf20Sopenharmony_ci resistors = "2k Ohm"; 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci case DS1343_TRICKLE_4K: 1748c2ecf20Sopenharmony_ci resistors = "4k Ohm"; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci default: 1788c2ecf20Sopenharmony_ci diodes = "disabled"; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return sprintf(buf, "%s %s\n", diodes, resistors); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic struct attribute *ds1343_attrs[] = { 1898c2ecf20Sopenharmony_ci &dev_attr_glitch_filter.attr, 1908c2ecf20Sopenharmony_ci &dev_attr_trickle_charger.attr, 1918c2ecf20Sopenharmony_ci NULL 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const struct attribute_group ds1343_attr_group = { 1958c2ecf20Sopenharmony_ci .attrs = ds1343_attrs, 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int ds1343_read_time(struct device *dev, struct rtc_time *dt) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev); 2018c2ecf20Sopenharmony_ci unsigned char buf[7]; 2028c2ecf20Sopenharmony_ci int res; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci res = regmap_bulk_read(priv->map, DS1343_SECONDS_REG, buf, 7); 2058c2ecf20Sopenharmony_ci if (res) 2068c2ecf20Sopenharmony_ci return res; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci dt->tm_sec = bcd2bin(buf[0]); 2098c2ecf20Sopenharmony_ci dt->tm_min = bcd2bin(buf[1]); 2108c2ecf20Sopenharmony_ci dt->tm_hour = bcd2bin(buf[2] & 0x3F); 2118c2ecf20Sopenharmony_ci dt->tm_wday = bcd2bin(buf[3]) - 1; 2128c2ecf20Sopenharmony_ci dt->tm_mday = bcd2bin(buf[4]); 2138c2ecf20Sopenharmony_ci dt->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; 2148c2ecf20Sopenharmony_ci dt->tm_year = bcd2bin(buf[6]) + 100; /* year offset from 1900 */ 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int ds1343_set_time(struct device *dev, struct rtc_time *dt) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev); 2228c2ecf20Sopenharmony_ci u8 buf[7]; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci buf[0] = bin2bcd(dt->tm_sec); 2258c2ecf20Sopenharmony_ci buf[1] = bin2bcd(dt->tm_min); 2268c2ecf20Sopenharmony_ci buf[2] = bin2bcd(dt->tm_hour) & 0x3F; 2278c2ecf20Sopenharmony_ci buf[3] = bin2bcd(dt->tm_wday + 1); 2288c2ecf20Sopenharmony_ci buf[4] = bin2bcd(dt->tm_mday); 2298c2ecf20Sopenharmony_ci buf[5] = bin2bcd(dt->tm_mon + 1); 2308c2ecf20Sopenharmony_ci buf[6] = bin2bcd(dt->tm_year - 100); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return regmap_bulk_write(priv->map, DS1343_SECONDS_REG, 2338c2ecf20Sopenharmony_ci buf, sizeof(buf)); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev); 2398c2ecf20Sopenharmony_ci unsigned char buf[4]; 2408c2ecf20Sopenharmony_ci unsigned int val; 2418c2ecf20Sopenharmony_ci int res; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (priv->irq <= 0) 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci res = regmap_read(priv->map, DS1343_STATUS_REG, &val); 2478c2ecf20Sopenharmony_ci if (res) 2488c2ecf20Sopenharmony_ci return res; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci alarm->pending = !!(val & DS1343_IRQF0); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci res = regmap_read(priv->map, DS1343_CONTROL_REG, &val); 2538c2ecf20Sopenharmony_ci if (res) 2548c2ecf20Sopenharmony_ci return res; 2558c2ecf20Sopenharmony_ci alarm->enabled = !!(val & DS1343_A0IE); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci res = regmap_bulk_read(priv->map, DS1343_ALM0_SEC_REG, buf, 4); 2588c2ecf20Sopenharmony_ci if (res) 2598c2ecf20Sopenharmony_ci return res; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci alarm->time.tm_sec = bcd2bin(buf[0]) & 0x7f; 2628c2ecf20Sopenharmony_ci alarm->time.tm_min = bcd2bin(buf[1]) & 0x7f; 2638c2ecf20Sopenharmony_ci alarm->time.tm_hour = bcd2bin(buf[2]) & 0x3f; 2648c2ecf20Sopenharmony_ci alarm->time.tm_mday = bcd2bin(buf[3]) & 0x3f; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev); 2728c2ecf20Sopenharmony_ci unsigned char buf[4]; 2738c2ecf20Sopenharmony_ci int res = 0; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (priv->irq <= 0) 2768c2ecf20Sopenharmony_ci return -EINVAL; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci res = regmap_update_bits(priv->map, DS1343_CONTROL_REG, DS1343_A0IE, 0); 2798c2ecf20Sopenharmony_ci if (res) 2808c2ecf20Sopenharmony_ci return res; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci buf[0] = bin2bcd(alarm->time.tm_sec); 2838c2ecf20Sopenharmony_ci buf[1] = bin2bcd(alarm->time.tm_min); 2848c2ecf20Sopenharmony_ci buf[2] = bin2bcd(alarm->time.tm_hour); 2858c2ecf20Sopenharmony_ci buf[3] = bin2bcd(alarm->time.tm_mday); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4); 2888c2ecf20Sopenharmony_ci if (res) 2898c2ecf20Sopenharmony_ci return res; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (alarm->enabled) 2928c2ecf20Sopenharmony_ci res = regmap_update_bits(priv->map, DS1343_CONTROL_REG, 2938c2ecf20Sopenharmony_ci DS1343_A0IE, DS1343_A0IE); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return res; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_get_drvdata(dev); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (priv->irq <= 0) 3038c2ecf20Sopenharmony_ci return -EINVAL; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return regmap_update_bits(priv->map, DS1343_CONTROL_REG, 3068c2ecf20Sopenharmony_ci DS1343_A0IE, enabled ? DS1343_A0IE : 0); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic irqreturn_t ds1343_thread(int irq, void *dev_id) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct ds1343_priv *priv = dev_id; 3128c2ecf20Sopenharmony_ci unsigned int stat; 3138c2ecf20Sopenharmony_ci int res = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci rtc_lock(priv->rtc); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); 3188c2ecf20Sopenharmony_ci if (res) 3198c2ecf20Sopenharmony_ci goto out; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (stat & DS1343_IRQF0) { 3228c2ecf20Sopenharmony_ci stat &= ~DS1343_IRQF0; 3238c2ecf20Sopenharmony_ci regmap_write(priv->map, DS1343_STATUS_REG, stat); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, DS1343_CONTROL_REG, 3288c2ecf20Sopenharmony_ci DS1343_A0IE, 0); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ciout: 3328c2ecf20Sopenharmony_ci rtc_unlock(priv->rtc); 3338c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic const struct rtc_class_ops ds1343_rtc_ops = { 3378c2ecf20Sopenharmony_ci .read_time = ds1343_read_time, 3388c2ecf20Sopenharmony_ci .set_time = ds1343_set_time, 3398c2ecf20Sopenharmony_ci .read_alarm = ds1343_read_alarm, 3408c2ecf20Sopenharmony_ci .set_alarm = ds1343_set_alarm, 3418c2ecf20Sopenharmony_ci .alarm_irq_enable = ds1343_alarm_irq_enable, 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int ds1343_probe(struct spi_device *spi) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct ds1343_priv *priv; 3478c2ecf20Sopenharmony_ci struct regmap_config config = { .reg_bits = 8, .val_bits = 8, 3488c2ecf20Sopenharmony_ci .write_flag_mask = 0x80, }; 3498c2ecf20Sopenharmony_ci unsigned int data; 3508c2ecf20Sopenharmony_ci int res; 3518c2ecf20Sopenharmony_ci struct nvmem_config nvmem_cfg = { 3528c2ecf20Sopenharmony_ci .name = "ds1343-", 3538c2ecf20Sopenharmony_ci .word_size = 1, 3548c2ecf20Sopenharmony_ci .stride = 1, 3558c2ecf20Sopenharmony_ci .size = DS1343_NVRAM_LEN, 3568c2ecf20Sopenharmony_ci .reg_read = ds1343_nvram_read, 3578c2ecf20Sopenharmony_ci .reg_write = ds1343_nvram_write, 3588c2ecf20Sopenharmony_ci }; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL); 3618c2ecf20Sopenharmony_ci if (!priv) 3628c2ecf20Sopenharmony_ci return -ENOMEM; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* RTC DS1347 works in spi mode 3 and 3658c2ecf20Sopenharmony_ci * its chip select is active high. Active high should be defined as 3668c2ecf20Sopenharmony_ci * "inverse polarity" as GPIO-based chip selects can be logically 3678c2ecf20Sopenharmony_ci * active high but inverted by the GPIO library. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci spi->mode |= SPI_MODE_3; 3708c2ecf20Sopenharmony_ci spi->mode ^= SPI_CS_HIGH; 3718c2ecf20Sopenharmony_ci spi->bits_per_word = 8; 3728c2ecf20Sopenharmony_ci res = spi_setup(spi); 3738c2ecf20Sopenharmony_ci if (res) 3748c2ecf20Sopenharmony_ci return res; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci spi_set_drvdata(spi, priv); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci priv->map = devm_regmap_init_spi(spi, &config); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (IS_ERR(priv->map)) { 3818c2ecf20Sopenharmony_ci dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n"); 3828c2ecf20Sopenharmony_ci return PTR_ERR(priv->map); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci res = regmap_read(priv->map, DS1343_SECONDS_REG, &data); 3868c2ecf20Sopenharmony_ci if (res) 3878c2ecf20Sopenharmony_ci return res; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci regmap_read(priv->map, DS1343_CONTROL_REG, &data); 3908c2ecf20Sopenharmony_ci data |= DS1343_INTCN; 3918c2ecf20Sopenharmony_ci data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE); 3928c2ecf20Sopenharmony_ci regmap_write(priv->map, DS1343_CONTROL_REG, data); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci regmap_read(priv->map, DS1343_STATUS_REG, &data); 3958c2ecf20Sopenharmony_ci data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0); 3968c2ecf20Sopenharmony_ci regmap_write(priv->map, DS1343_STATUS_REG, data); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci priv->rtc = devm_rtc_allocate_device(&spi->dev); 3998c2ecf20Sopenharmony_ci if (IS_ERR(priv->rtc)) 4008c2ecf20Sopenharmony_ci return PTR_ERR(priv->rtc); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci priv->rtc->nvram_old_abi = true; 4038c2ecf20Sopenharmony_ci priv->rtc->ops = &ds1343_rtc_ops; 4048c2ecf20Sopenharmony_ci priv->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 4058c2ecf20Sopenharmony_ci priv->rtc->range_max = RTC_TIMESTAMP_END_2099; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci res = rtc_add_group(priv->rtc, &ds1343_attr_group); 4088c2ecf20Sopenharmony_ci if (res) 4098c2ecf20Sopenharmony_ci dev_err(&spi->dev, 4108c2ecf20Sopenharmony_ci "unable to create sysfs entries for rtc ds1343\n"); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci res = rtc_register_device(priv->rtc); 4138c2ecf20Sopenharmony_ci if (res) 4148c2ecf20Sopenharmony_ci return res; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci nvmem_cfg.priv = priv; 4178c2ecf20Sopenharmony_ci rtc_nvmem_register(priv->rtc, &nvmem_cfg); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci priv->irq = spi->irq; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (priv->irq >= 0) { 4228c2ecf20Sopenharmony_ci res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, 4238c2ecf20Sopenharmony_ci ds1343_thread, IRQF_ONESHOT, 4248c2ecf20Sopenharmony_ci "ds1343", priv); 4258c2ecf20Sopenharmony_ci if (res) { 4268c2ecf20Sopenharmony_ci priv->irq = -1; 4278c2ecf20Sopenharmony_ci dev_err(&spi->dev, 4288c2ecf20Sopenharmony_ci "unable to request irq for rtc ds1343\n"); 4298c2ecf20Sopenharmony_ci } else { 4308c2ecf20Sopenharmony_ci device_init_wakeup(&spi->dev, true); 4318c2ecf20Sopenharmony_ci dev_pm_set_wake_irq(&spi->dev, spi->irq); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic int ds1343_remove(struct spi_device *spi) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci dev_pm_clear_wake_irq(&spi->dev); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int ds1343_suspend(struct device *dev) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (spi->irq >= 0 && device_may_wakeup(dev)) 4528c2ecf20Sopenharmony_ci enable_irq_wake(spi->irq); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int ds1343_resume(struct device *dev) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (spi->irq >= 0 && device_may_wakeup(dev)) 4628c2ecf20Sopenharmony_ci disable_irq_wake(spi->irq); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci#endif 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct spi_driver ds1343_driver = { 4728c2ecf20Sopenharmony_ci .driver = { 4738c2ecf20Sopenharmony_ci .name = "ds1343", 4748c2ecf20Sopenharmony_ci .pm = &ds1343_pm, 4758c2ecf20Sopenharmony_ci }, 4768c2ecf20Sopenharmony_ci .probe = ds1343_probe, 4778c2ecf20Sopenharmony_ci .remove = ds1343_remove, 4788c2ecf20Sopenharmony_ci .id_table = ds1343_id, 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cimodule_spi_driver(ds1343_driver); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DS1343 RTC SPI Driver"); 4848c2ecf20Sopenharmony_ciMODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>," 4858c2ecf20Sopenharmony_ci "Ankur Srivastava <sankurece@gmail.com>"); 4868c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 487