17dc679efSNobuhiro Iwamatsu // SPDX-License-Identifier: GPL-2.0 2453b4c6dSJonas Jensen /* 3453b4c6dSJonas Jensen * MOXA ART RTC driver. 4453b4c6dSJonas Jensen * 5453b4c6dSJonas Jensen * Copyright (C) 2013 Jonas Jensen 6453b4c6dSJonas Jensen * 7453b4c6dSJonas Jensen * Jonas Jensen <jonas.jensen@gmail.com> 8453b4c6dSJonas Jensen * 9453b4c6dSJonas Jensen * Based on code from 10453b4c6dSJonas Jensen * Moxa Technology Co., Ltd. <www.moxa.com> 11453b4c6dSJonas Jensen */ 12453b4c6dSJonas Jensen 13*2985cda8SDmitry Torokhov #include <linux/err.h> 14453b4c6dSJonas Jensen #include <linux/init.h> 15453b4c6dSJonas Jensen #include <linux/kernel.h> 16453b4c6dSJonas Jensen #include <linux/delay.h> 17453b4c6dSJonas Jensen #include <linux/rtc.h> 18453b4c6dSJonas Jensen #include <linux/platform_device.h> 19453b4c6dSJonas Jensen #include <linux/module.h> 20*2985cda8SDmitry Torokhov #include <linux/mod_devicetable.h> 21*2985cda8SDmitry Torokhov #include <linux/gpio/consumer.h> 22453b4c6dSJonas Jensen 23453b4c6dSJonas Jensen #define GPIO_RTC_RESERVED 0x0C 24453b4c6dSJonas Jensen #define GPIO_RTC_DATA_SET 0x10 25453b4c6dSJonas Jensen #define GPIO_RTC_DATA_CLEAR 0x14 26453b4c6dSJonas Jensen #define GPIO_RTC_PIN_PULL_ENABLE 0x18 27453b4c6dSJonas Jensen #define GPIO_RTC_PIN_PULL_TYPE 0x1C 28453b4c6dSJonas Jensen #define GPIO_RTC_INT_ENABLE 0x20 29453b4c6dSJonas Jensen #define GPIO_RTC_INT_RAW_STATE 0x24 30453b4c6dSJonas Jensen #define GPIO_RTC_INT_MASKED_STATE 0x28 31453b4c6dSJonas Jensen #define GPIO_RTC_INT_MASK 0x2C 32453b4c6dSJonas Jensen #define GPIO_RTC_INT_CLEAR 0x30 33453b4c6dSJonas Jensen #define GPIO_RTC_INT_TRIGGER 0x34 34453b4c6dSJonas Jensen #define GPIO_RTC_INT_BOTH 0x38 35453b4c6dSJonas Jensen #define GPIO_RTC_INT_RISE_NEG 0x3C 36453b4c6dSJonas Jensen #define GPIO_RTC_BOUNCE_ENABLE 0x40 37453b4c6dSJonas Jensen #define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 38453b4c6dSJonas Jensen #define GPIO_RTC_PROTECT_W 0x8E 39453b4c6dSJonas Jensen #define GPIO_RTC_PROTECT_R 0x8F 40453b4c6dSJonas Jensen #define GPIO_RTC_YEAR_W 0x8C 41453b4c6dSJonas Jensen #define GPIO_RTC_YEAR_R 0x8D 42453b4c6dSJonas Jensen #define GPIO_RTC_DAY_W 0x8A 43453b4c6dSJonas Jensen #define GPIO_RTC_DAY_R 0x8B 44453b4c6dSJonas Jensen #define GPIO_RTC_MONTH_W 0x88 45453b4c6dSJonas Jensen #define GPIO_RTC_MONTH_R 0x89 46453b4c6dSJonas Jensen #define GPIO_RTC_DATE_W 0x86 47453b4c6dSJonas Jensen #define GPIO_RTC_DATE_R 0x87 48453b4c6dSJonas Jensen #define GPIO_RTC_HOURS_W 0x84 49453b4c6dSJonas Jensen #define GPIO_RTC_HOURS_R 0x85 50453b4c6dSJonas Jensen #define GPIO_RTC_MINUTES_W 0x82 51453b4c6dSJonas Jensen #define GPIO_RTC_MINUTES_R 0x83 52453b4c6dSJonas Jensen #define GPIO_RTC_SECONDS_W 0x80 53453b4c6dSJonas Jensen #define GPIO_RTC_SECONDS_R 0x81 54453b4c6dSJonas Jensen #define GPIO_RTC_DELAY_TIME 8 55453b4c6dSJonas Jensen 56453b4c6dSJonas Jensen struct moxart_rtc { 57453b4c6dSJonas Jensen struct rtc_device *rtc; 58453b4c6dSJonas Jensen spinlock_t rtc_lock; 59*2985cda8SDmitry Torokhov struct gpio_desc *gpio_data; 60*2985cda8SDmitry Torokhov struct gpio_desc *gpio_sclk; 61*2985cda8SDmitry Torokhov struct gpio_desc *gpio_reset; 62453b4c6dSJonas Jensen }; 63453b4c6dSJonas Jensen 64453b4c6dSJonas Jensen static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, 65453b4c6dSJonas Jensen 212, 243, 273, 304, 334 }; 66453b4c6dSJonas Jensen 67453b4c6dSJonas Jensen static void moxart_rtc_write_byte(struct device *dev, u8 data) 68453b4c6dSJonas Jensen { 69453b4c6dSJonas Jensen struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); 70453b4c6dSJonas Jensen int i; 71453b4c6dSJonas Jensen 72453b4c6dSJonas Jensen for (i = 0; i < 8; i++, data >>= 1) { 73*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_sclk, 0); 74*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); 75453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 76*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_sclk, 1); 77453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 78453b4c6dSJonas Jensen } 79453b4c6dSJonas Jensen } 80453b4c6dSJonas Jensen 81453b4c6dSJonas Jensen static u8 moxart_rtc_read_byte(struct device *dev) 82453b4c6dSJonas Jensen { 83453b4c6dSJonas Jensen struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); 84453b4c6dSJonas Jensen int i; 85453b4c6dSJonas Jensen u8 data = 0; 86453b4c6dSJonas Jensen 87453b4c6dSJonas Jensen for (i = 0; i < 8; i++) { 88*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_sclk, 0); 89453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 90*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_sclk, 1); 91453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 92*2985cda8SDmitry Torokhov if (gpiod_get_value(moxart_rtc->gpio_data)) 93453b4c6dSJonas Jensen data |= (1 << i); 94453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 95453b4c6dSJonas Jensen } 96453b4c6dSJonas Jensen return data; 97453b4c6dSJonas Jensen } 98453b4c6dSJonas Jensen 99453b4c6dSJonas Jensen static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) 100453b4c6dSJonas Jensen { 101453b4c6dSJonas Jensen struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); 102453b4c6dSJonas Jensen u8 data; 103453b4c6dSJonas Jensen unsigned long flags; 104453b4c6dSJonas Jensen 105453b4c6dSJonas Jensen local_irq_save(flags); 106453b4c6dSJonas Jensen 107*2985cda8SDmitry Torokhov gpiod_direction_output(moxart_rtc->gpio_data, 0); 108*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_reset, 1); 109453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 110453b4c6dSJonas Jensen moxart_rtc_write_byte(dev, cmd); 111*2985cda8SDmitry Torokhov gpiod_direction_input(moxart_rtc->gpio_data); 112453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 113453b4c6dSJonas Jensen data = moxart_rtc_read_byte(dev); 114*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_sclk, 0); 115*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_reset, 0); 116453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 117453b4c6dSJonas Jensen 118453b4c6dSJonas Jensen local_irq_restore(flags); 119453b4c6dSJonas Jensen 120453b4c6dSJonas Jensen return data; 121453b4c6dSJonas Jensen } 122453b4c6dSJonas Jensen 123453b4c6dSJonas Jensen static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) 124453b4c6dSJonas Jensen { 125453b4c6dSJonas Jensen struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); 126453b4c6dSJonas Jensen unsigned long flags; 127453b4c6dSJonas Jensen 128453b4c6dSJonas Jensen local_irq_save(flags); 129453b4c6dSJonas Jensen 130*2985cda8SDmitry Torokhov gpiod_direction_output(moxart_rtc->gpio_data, 0); 131*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_reset, 1); 132453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 133453b4c6dSJonas Jensen moxart_rtc_write_byte(dev, cmd); 134453b4c6dSJonas Jensen moxart_rtc_write_byte(dev, data); 135*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_sclk, 0); 136*2985cda8SDmitry Torokhov gpiod_set_value(moxart_rtc->gpio_reset, 0); 137453b4c6dSJonas Jensen udelay(GPIO_RTC_DELAY_TIME); 138453b4c6dSJonas Jensen 139453b4c6dSJonas Jensen local_irq_restore(flags); 140453b4c6dSJonas Jensen } 141453b4c6dSJonas Jensen 142453b4c6dSJonas Jensen static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) 143453b4c6dSJonas Jensen { 144453b4c6dSJonas Jensen struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); 145453b4c6dSJonas Jensen 146453b4c6dSJonas Jensen spin_lock_irq(&moxart_rtc->rtc_lock); 147453b4c6dSJonas Jensen 148453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0); 149453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_YEAR_W, 150453b4c6dSJonas Jensen (((tm->tm_year - 100) / 10) << 4) | 151453b4c6dSJonas Jensen ((tm->tm_year - 100) % 10)); 152453b4c6dSJonas Jensen 153453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_MONTH_W, 154453b4c6dSJonas Jensen (((tm->tm_mon + 1) / 10) << 4) | 155453b4c6dSJonas Jensen ((tm->tm_mon + 1) % 10)); 156453b4c6dSJonas Jensen 157453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_DATE_W, 158453b4c6dSJonas Jensen ((tm->tm_mday / 10) << 4) | 159453b4c6dSJonas Jensen (tm->tm_mday % 10)); 160453b4c6dSJonas Jensen 161453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_HOURS_W, 162453b4c6dSJonas Jensen ((tm->tm_hour / 10) << 4) | 163453b4c6dSJonas Jensen (tm->tm_hour % 10)); 164453b4c6dSJonas Jensen 165453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_MINUTES_W, 166453b4c6dSJonas Jensen ((tm->tm_min / 10) << 4) | 167453b4c6dSJonas Jensen (tm->tm_min % 10)); 168453b4c6dSJonas Jensen 169453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_SECONDS_W, 170453b4c6dSJonas Jensen ((tm->tm_sec / 10) << 4) | 171453b4c6dSJonas Jensen (tm->tm_sec % 10)); 172453b4c6dSJonas Jensen 173453b4c6dSJonas Jensen moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0x80); 174453b4c6dSJonas Jensen 175453b4c6dSJonas Jensen spin_unlock_irq(&moxart_rtc->rtc_lock); 176453b4c6dSJonas Jensen 177453b4c6dSJonas Jensen dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" 178453b4c6dSJonas Jensen "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n", 179453b4c6dSJonas Jensen __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, 180453b4c6dSJonas Jensen tm->tm_hour, tm->tm_min, tm->tm_sec); 181453b4c6dSJonas Jensen 182453b4c6dSJonas Jensen return 0; 183453b4c6dSJonas Jensen } 184453b4c6dSJonas Jensen 185453b4c6dSJonas Jensen static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) 186453b4c6dSJonas Jensen { 187453b4c6dSJonas Jensen struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); 188453b4c6dSJonas Jensen unsigned char v; 189453b4c6dSJonas Jensen 190453b4c6dSJonas Jensen spin_lock_irq(&moxart_rtc->rtc_lock); 191453b4c6dSJonas Jensen 192453b4c6dSJonas Jensen v = moxart_rtc_read_register(dev, GPIO_RTC_SECONDS_R); 193453b4c6dSJonas Jensen tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); 194453b4c6dSJonas Jensen 195453b4c6dSJonas Jensen v = moxart_rtc_read_register(dev, GPIO_RTC_MINUTES_R); 196453b4c6dSJonas Jensen tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); 197453b4c6dSJonas Jensen 198453b4c6dSJonas Jensen v = moxart_rtc_read_register(dev, GPIO_RTC_HOURS_R); 199453b4c6dSJonas Jensen if (v & 0x80) { /* 12-hour mode */ 200453b4c6dSJonas Jensen tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); 201453b4c6dSJonas Jensen if (v & 0x20) { /* PM mode */ 202453b4c6dSJonas Jensen tm->tm_hour += 12; 203453b4c6dSJonas Jensen if (tm->tm_hour >= 24) 204453b4c6dSJonas Jensen tm->tm_hour = 0; 205453b4c6dSJonas Jensen } 206453b4c6dSJonas Jensen } else { /* 24-hour mode */ 207453b4c6dSJonas Jensen tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); 208453b4c6dSJonas Jensen } 209453b4c6dSJonas Jensen 210453b4c6dSJonas Jensen v = moxart_rtc_read_register(dev, GPIO_RTC_DATE_R); 211453b4c6dSJonas Jensen tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); 212453b4c6dSJonas Jensen 213453b4c6dSJonas Jensen v = moxart_rtc_read_register(dev, GPIO_RTC_MONTH_R); 214453b4c6dSJonas Jensen tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); 215453b4c6dSJonas Jensen tm->tm_mon--; 216453b4c6dSJonas Jensen 217453b4c6dSJonas Jensen v = moxart_rtc_read_register(dev, GPIO_RTC_YEAR_R); 218453b4c6dSJonas Jensen tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); 219453b4c6dSJonas Jensen tm->tm_year += 100; 220453b4c6dSJonas Jensen if (tm->tm_year <= 69) 221453b4c6dSJonas Jensen tm->tm_year += 100; 222453b4c6dSJonas Jensen 223453b4c6dSJonas Jensen v = moxart_rtc_read_register(dev, GPIO_RTC_DAY_R); 224453b4c6dSJonas Jensen tm->tm_wday = (v & 0x0f) - 1; 225453b4c6dSJonas Jensen tm->tm_yday = day_of_year[tm->tm_mon]; 226453b4c6dSJonas Jensen tm->tm_yday += (tm->tm_mday - 1); 227453b4c6dSJonas Jensen if (tm->tm_mon >= 2) { 228453b4c6dSJonas Jensen if (!(tm->tm_year % 4) && (tm->tm_year % 100)) 229453b4c6dSJonas Jensen tm->tm_yday++; 230453b4c6dSJonas Jensen } 231453b4c6dSJonas Jensen 232453b4c6dSJonas Jensen tm->tm_isdst = 0; 233453b4c6dSJonas Jensen 234453b4c6dSJonas Jensen spin_unlock_irq(&moxart_rtc->rtc_lock); 235453b4c6dSJonas Jensen 236453b4c6dSJonas Jensen return 0; 237453b4c6dSJonas Jensen } 238453b4c6dSJonas Jensen 239453b4c6dSJonas Jensen static const struct rtc_class_ops moxart_rtc_ops = { 240453b4c6dSJonas Jensen .read_time = moxart_rtc_read_time, 241453b4c6dSJonas Jensen .set_time = moxart_rtc_set_time, 242453b4c6dSJonas Jensen }; 243453b4c6dSJonas Jensen 244453b4c6dSJonas Jensen static int moxart_rtc_probe(struct platform_device *pdev) 245453b4c6dSJonas Jensen { 246453b4c6dSJonas Jensen struct moxart_rtc *moxart_rtc; 247453b4c6dSJonas Jensen int ret = 0; 248453b4c6dSJonas Jensen 249453b4c6dSJonas Jensen moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL); 2504410af6eSJingoo Han if (!moxart_rtc) 251453b4c6dSJonas Jensen return -ENOMEM; 252453b4c6dSJonas Jensen 253*2985cda8SDmitry Torokhov moxart_rtc->gpio_data = devm_gpiod_get(&pdev->dev, "rtc-data", 254*2985cda8SDmitry Torokhov GPIOD_IN); 255*2985cda8SDmitry Torokhov ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_data); 256*2985cda8SDmitry Torokhov if (ret) { 257*2985cda8SDmitry Torokhov dev_err(&pdev->dev, "can't get rtc data gpio: %d\n", ret); 258*2985cda8SDmitry Torokhov return ret; 259453b4c6dSJonas Jensen } 260453b4c6dSJonas Jensen 261*2985cda8SDmitry Torokhov moxart_rtc->gpio_sclk = devm_gpiod_get(&pdev->dev, "rtc-sclk", 262*2985cda8SDmitry Torokhov GPIOD_ASIS); 263*2985cda8SDmitry Torokhov ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_sclk); 264*2985cda8SDmitry Torokhov if (ret) { 265*2985cda8SDmitry Torokhov dev_err(&pdev->dev, "can't get rtc sclk gpio: %d\n", ret); 266*2985cda8SDmitry Torokhov return ret; 267453b4c6dSJonas Jensen } 268453b4c6dSJonas Jensen 269*2985cda8SDmitry Torokhov moxart_rtc->gpio_reset = devm_gpiod_get(&pdev->dev, "rtc-reset", 270*2985cda8SDmitry Torokhov GPIOD_ASIS); 271*2985cda8SDmitry Torokhov ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_reset); 272*2985cda8SDmitry Torokhov if (ret) { 273*2985cda8SDmitry Torokhov dev_err(&pdev->dev, "can't get rtc reset gpio: %d\n", ret); 274*2985cda8SDmitry Torokhov return ret; 275453b4c6dSJonas Jensen } 276453b4c6dSJonas Jensen 277453b4c6dSJonas Jensen spin_lock_init(&moxart_rtc->rtc_lock); 278453b4c6dSJonas Jensen platform_set_drvdata(pdev, moxart_rtc); 279453b4c6dSJonas Jensen 280453b4c6dSJonas Jensen moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, 281453b4c6dSJonas Jensen &moxart_rtc_ops, 282453b4c6dSJonas Jensen THIS_MODULE); 283453b4c6dSJonas Jensen if (IS_ERR(moxart_rtc->rtc)) { 284453b4c6dSJonas Jensen dev_err(&pdev->dev, "devm_rtc_device_register failed\n"); 285453b4c6dSJonas Jensen return PTR_ERR(moxart_rtc->rtc); 286453b4c6dSJonas Jensen } 287453b4c6dSJonas Jensen 288453b4c6dSJonas Jensen return 0; 289453b4c6dSJonas Jensen } 290453b4c6dSJonas Jensen 291453b4c6dSJonas Jensen static const struct of_device_id moxart_rtc_match[] = { 292453b4c6dSJonas Jensen { .compatible = "moxa,moxart-rtc" }, 293453b4c6dSJonas Jensen { }, 294453b4c6dSJonas Jensen }; 29573798d5cSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, moxart_rtc_match); 296453b4c6dSJonas Jensen 297453b4c6dSJonas Jensen static struct platform_driver moxart_rtc_driver = { 298453b4c6dSJonas Jensen .probe = moxart_rtc_probe, 299453b4c6dSJonas Jensen .driver = { 300453b4c6dSJonas Jensen .name = "moxart-rtc", 301453b4c6dSJonas Jensen .of_match_table = moxart_rtc_match, 302453b4c6dSJonas Jensen }, 303453b4c6dSJonas Jensen }; 304453b4c6dSJonas Jensen module_platform_driver(moxart_rtc_driver); 305453b4c6dSJonas Jensen 306453b4c6dSJonas Jensen MODULE_DESCRIPTION("MOXART RTC driver"); 307453b4c6dSJonas Jensen MODULE_LICENSE("GPL"); 308453b4c6dSJonas Jensen MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); 309