Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers/rtc/rtc-ds1307.c: add alarm support for mcp7941x chips

Add alarm support for the Microchip RTC devices MCP794xx. Note that two
programmable alarms are provided by the chip but only one is used by the
driver.

Signed-off-by: Simon Guinot <simon.guinot@sequanux.org>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Gregory Clement <gregory.clement@free-electrons.com>
Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Simon Guinot and committed by
Linus Torvalds
1d1945d2 5ea73514

+182 -1
+182 -1
drivers/rtc/rtc-ds1307.c
··· 154 154 .alarm = 1, 155 155 }, 156 156 [mcp7941x] = { 157 + .alarm = 1, 157 158 /* this is battery backed SRAM */ 158 159 .nvram_offset = 0x20, 159 160 .nvram_size = 0x40, ··· 607 606 608 607 /*----------------------------------------------------------------------*/ 609 608 609 + /* 610 + * Alarm support for mcp7941x devices. 611 + */ 612 + 613 + #define MCP7941X_REG_CONTROL 0x07 614 + # define MCP7941X_BIT_ALM0_EN 0x10 615 + # define MCP7941X_BIT_ALM1_EN 0x20 616 + #define MCP7941X_REG_ALARM0_BASE 0x0a 617 + #define MCP7941X_REG_ALARM0_CTRL 0x0d 618 + #define MCP7941X_REG_ALARM1_BASE 0x11 619 + #define MCP7941X_REG_ALARM1_CTRL 0x14 620 + # define MCP7941X_BIT_ALMX_IF (1 << 3) 621 + # define MCP7941X_BIT_ALMX_C0 (1 << 4) 622 + # define MCP7941X_BIT_ALMX_C1 (1 << 5) 623 + # define MCP7941X_BIT_ALMX_C2 (1 << 6) 624 + # define MCP7941X_BIT_ALMX_POL (1 << 7) 625 + # define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \ 626 + MCP7941X_BIT_ALMX_C1 | \ 627 + MCP7941X_BIT_ALMX_C2) 628 + 629 + static void mcp7941x_work(struct work_struct *work) 630 + { 631 + struct ds1307 *ds1307 = container_of(work, struct ds1307, work); 632 + struct i2c_client *client = ds1307->client; 633 + int reg, ret; 634 + 635 + mutex_lock(&ds1307->rtc->ops_lock); 636 + 637 + /* Check and clear alarm 0 interrupt flag. */ 638 + reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL); 639 + if (reg < 0) 640 + goto out; 641 + if (!(reg & MCP7941X_BIT_ALMX_IF)) 642 + goto out; 643 + reg &= ~MCP7941X_BIT_ALMX_IF; 644 + ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg); 645 + if (ret < 0) 646 + goto out; 647 + 648 + /* Disable alarm 0. */ 649 + reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); 650 + if (reg < 0) 651 + goto out; 652 + reg &= ~MCP7941X_BIT_ALM0_EN; 653 + ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); 654 + if (ret < 0) 655 + goto out; 656 + 657 + rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); 658 + 659 + out: 660 + if (test_bit(HAS_ALARM, &ds1307->flags)) 661 + enable_irq(client->irq); 662 + mutex_unlock(&ds1307->rtc->ops_lock); 663 + } 664 + 665 + static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t) 666 + { 667 + struct i2c_client *client = to_i2c_client(dev); 668 + struct ds1307 *ds1307 = i2c_get_clientdata(client); 669 + u8 *regs = ds1307->regs; 670 + int ret; 671 + 672 + if (!test_bit(HAS_ALARM, &ds1307->flags)) 673 + return -EINVAL; 674 + 675 + /* Read control and alarm 0 registers. */ 676 + ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); 677 + if (ret < 0) 678 + return ret; 679 + 680 + t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN); 681 + 682 + /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ 683 + t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f); 684 + t->time.tm_min = bcd2bin(ds1307->regs[4] & 0x7f); 685 + t->time.tm_hour = bcd2bin(ds1307->regs[5] & 0x3f); 686 + t->time.tm_wday = bcd2bin(ds1307->regs[6] & 0x7) - 1; 687 + t->time.tm_mday = bcd2bin(ds1307->regs[7] & 0x3f); 688 + t->time.tm_mon = bcd2bin(ds1307->regs[8] & 0x1f) - 1; 689 + t->time.tm_year = -1; 690 + t->time.tm_yday = -1; 691 + t->time.tm_isdst = -1; 692 + 693 + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " 694 + "enabled=%d polarity=%d irq=%d match=%d\n", __func__, 695 + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, 696 + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled, 697 + !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL), 698 + !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF), 699 + (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4); 700 + 701 + return 0; 702 + } 703 + 704 + static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t) 705 + { 706 + struct i2c_client *client = to_i2c_client(dev); 707 + struct ds1307 *ds1307 = i2c_get_clientdata(client); 708 + unsigned char *regs = ds1307->regs; 709 + int ret; 710 + 711 + if (!test_bit(HAS_ALARM, &ds1307->flags)) 712 + return -EINVAL; 713 + 714 + dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " 715 + "enabled=%d pending=%d\n", __func__, 716 + t->time.tm_sec, t->time.tm_min, t->time.tm_hour, 717 + t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, 718 + t->enabled, t->pending); 719 + 720 + /* Read control and alarm 0 registers. */ 721 + ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); 722 + if (ret < 0) 723 + return ret; 724 + 725 + /* Set alarm 0, using 24-hour and day-of-month modes. */ 726 + regs[3] = bin2bcd(t->time.tm_sec); 727 + regs[4] = bin2bcd(t->time.tm_min); 728 + regs[5] = bin2bcd(t->time.tm_hour); 729 + regs[6] = bin2bcd(t->time.tm_wday) + 1; 730 + regs[7] = bin2bcd(t->time.tm_mday); 731 + regs[8] = bin2bcd(t->time.tm_mon) + 1; 732 + 733 + /* Clear the alarm 0 interrupt flag. */ 734 + regs[6] &= ~MCP7941X_BIT_ALMX_IF; 735 + /* Set alarm match: second, minute, hour, day, date, month. */ 736 + regs[6] |= MCP7941X_MSK_ALMX_MATCH; 737 + 738 + if (t->enabled) 739 + regs[0] |= MCP7941X_BIT_ALM0_EN; 740 + else 741 + regs[0] &= ~MCP7941X_BIT_ALM0_EN; 742 + 743 + ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs); 744 + if (ret < 0) 745 + return ret; 746 + 747 + return 0; 748 + } 749 + 750 + static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled) 751 + { 752 + struct i2c_client *client = to_i2c_client(dev); 753 + struct ds1307 *ds1307 = i2c_get_clientdata(client); 754 + int reg; 755 + 756 + if (!test_bit(HAS_ALARM, &ds1307->flags)) 757 + return -EINVAL; 758 + 759 + reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); 760 + if (reg < 0) 761 + return reg; 762 + 763 + if (enabled) 764 + reg |= MCP7941X_BIT_ALM0_EN; 765 + else 766 + reg &= ~MCP7941X_BIT_ALM0_EN; 767 + 768 + return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); 769 + } 770 + 771 + static const struct rtc_class_ops mcp7941x_rtc_ops = { 772 + .read_time = ds1307_get_time, 773 + .set_time = ds1307_set_time, 774 + .read_alarm = mcp7941x_read_alarm, 775 + .set_alarm = mcp7941x_set_alarm, 776 + .alarm_irq_enable = mcp7941x_alarm_irq_enable, 777 + }; 778 + 779 + /*----------------------------------------------------------------------*/ 780 + 610 781 static ssize_t 611 782 ds1307_nvram_read(struct file *filp, struct kobject *kobj, 612 783 struct bin_attribute *attr, ··· 851 678 [ds_1339] = DS1339_BIT_BBSQI, 852 679 [ds_3231] = DS3231_BIT_BBSQW, 853 680 }; 681 + const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops; 854 682 855 683 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) 856 684 && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) ··· 990 816 case ds_1388: 991 817 ds1307->offset = 1; /* Seconds starts at 1 */ 992 818 break; 819 + case mcp7941x: 820 + rtc_ops = &mcp7941x_rtc_ops; 821 + if (ds1307->client->irq > 0 && chip->alarm) { 822 + INIT_WORK(&ds1307->work, mcp7941x_work); 823 + want_irq = true; 824 + } 825 + break; 993 826 default: 994 827 break; 995 828 } ··· 1110 929 1111 930 device_set_wakeup_capable(&client->dev, want_irq); 1112 931 ds1307->rtc = devm_rtc_device_register(&client->dev, client->name, 1113 - &ds13xx_rtc_ops, THIS_MODULE); 932 + rtc_ops, THIS_MODULE); 1114 933 if (IS_ERR(ds1307->rtc)) { 1115 934 return PTR_ERR(ds1307->rtc); 1116 935 }