From patchwork Thu Feb 13 09:14:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 319924 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-pd0-x239.google.com (mail-pd0-x239.google.com [IPv6:2607:f8b0:400e:c02::239]) (using TLSv1 with cipher ECDHE-RSA-RC4-SHA (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 557242C0096 for ; Thu, 13 Feb 2014 20:14:34 +1100 (EST) Received: by mail-pd0-f185.google.com with SMTP id z10sf2834724pdj.22 for ; Thu, 13 Feb 2014 01:14:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20120806; h=mime-version:from:to:cc:subject:date:message-id:in-reply-to :references:x-original-sender:x-original-authentication-results :reply-to:precedence:mailing-list:list-id:list-post:list-help :list-archive:sender:list-subscribe:list-unsubscribe:content-type; bh=HlMLa7U3BsTg/K9+eY0O5t58FHfwdtfhVKpfK310jUk=; b=Xqt4AquRfgBm+3uLDrnfphMyhMtE1D/ORWOrGVivqmWF1NSd05yUIiDnw9z6YPUsMS YOWBrvjPYr/pA8DVySjNByN3DA1dqGKugEBOFx67ag1SK8DSjqPP8c16pTr/kyqJoxUI vMPDNVA5g47Od1RqXV9MizKptcy8scEgWeJsUf28GlHK+Ps4FQZqCzSm4Zd2zFpwa2tU 53PqftzC6hRVBk+C+Qnmm+74P2XaAsCrQw3Y24EqxWRkJLh++3L+KhyLlepVhr0oilDN b0qa0OH49z2L8NXYfWdwq1zFWm3DbCsnyWt9W69XjXmzxeccusxlhwBcCtsYwqAH9J8q Bvpw== X-Received: by 10.50.93.37 with SMTP id cr5mr43744igb.8.1392282871890; Thu, 13 Feb 2014 01:14:31 -0800 (PST) MIME-Version: 1.0 X-BeenThere: rtc-linux@googlegroups.com Received: by 10.50.138.100 with SMTP id qp4ls366542igb.43.canary; Thu, 13 Feb 2014 01:14:31 -0800 (PST) X-Received: by 10.66.222.105 with SMTP id ql9mr139655pac.9.1392282871323; Thu, 13 Feb 2014 01:14:31 -0800 (PST) Received: from mailout2.w1.samsung.com (mailout2.w1.samsung.com. [210.118.77.12]) by gmr-mx.google.com with ESMTPS id pt3si452901pac.0.2014.02.13.01.14.31 for (version=TLSv1 cipher=RC4-MD5 bits=128/128); Thu, 13 Feb 2014 01:14:31 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of k.kozlowski@samsung.com designates 210.118.77.12 as permitted sender) client-ip=210.118.77.12; Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout2.w1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0N0X00CGGGC1HE40@mailout2.w1.samsung.com> for rtc-linux@googlegroups.com; Thu, 13 Feb 2014 09:14:25 +0000 (GMT) X-AuditID: cbfec7f4-b7f796d000005a13-a4-52fc8cf51cb1 Received: from eusync1.samsung.com ( [203.254.199.211]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id DB.3D.23059.5FC8CF25; Thu, 13 Feb 2014 09:14:29 +0000 (GMT) Received: from AMDC1943.digital.local ([106.116.151.171]) by eusync1.samsung.com (Oracle Communications Messaging Server 7u4-23.01(7.0.4.23.0) 64bit (built Aug 10 2011)) with ESMTPA id <0N0X002E0GBT6O90@eusync1.samsung.com>; Thu, 13 Feb 2014 09:14:28 +0000 (GMT) From: Krzysztof Kozlowski To: Sangbeom Kim , Samuel Ortiz , Lee Jones , linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org Cc: Kyungmin Park , Marek Szyprowski , Bartlomiej Zolnierkiewicz , Krzysztof Kozlowski , Alessandro Zummo , rtc-linux@googlegroups.com Subject: [rtc-linux] [PATCH v2 13/14] rtc: s5m: Support different register layout Date: Thu, 13 Feb 2014 10:14:06 +0100 Message-id: <1392282847-25444-14-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1392282847-25444-1-git-send-email-k.kozlowski@samsung.com> References: <1392282847-25444-1-git-send-email-k.kozlowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFuphluLIzCtJLcpLzFFi42I5/e/4Zd2vPX+CDH5vZ7dYcvEqu8XGGetZ LV6/MLQ42/SG3eL+16OMFpd3zWGzmHF+H5PF2iN32S32d3YwWpzuZrW4uOILkwO3x56JJ9k8 7lzbw+Yx72SgR9+WVYwe0+f9ZPL4vEkugC2KyyYlNSezLLVI3y6BK2PbpD+MBX9jKu6+b2ds YHzv1cXIySEhYCLx+u9LNghbTOLCvfVANheHkMBSRokZjX+ZIZw+JolJjdNYQKrYBIwlNi9f AlYlIrCZUWLx96usIA6zQA+TxLX2uUBVHBzCAq4S/T/BxrIIqEqc3dgEZvMKeEicvNLEDlIi IaAgMWeSDUiYEyj878dvZhBbSMBdomfxLPYJjLwLGBlWMYqmliYXFCel5xrqFSfmFpfmpesl 5+duYoSE4JcdjIuPWR1iFOBgVOLhtVj2O0iINbGsuDL3EKMEB7OSCK+MxJ8gId6UxMqq1KL8 +KLSnNTiQ4xMHJxSDYwpto8DzXzzZ5X7XFnesN0w1mXlzZbSO2IPFs5Ifbl0i3iUY3KnnMac /mVd26ZInsriuGy5sOGH1kXlm+ZiQsl7LaaInL1q9NfL/MI12Tffd8Wczdi81/3Z1vWlcdY+ Yev7BSRPHxF9EXVJ5q/kvYTFNwOYOH98Kf3wo7rC7EJ3ra1/XBHzWlslluKMREMt5qLiRAA1 4x+6HwIAAA== X-Original-Sender: k.kozlowski@samsung.com X-Original-Authentication-Results: gmr-mx.google.com; spf=pass (google.com: best guess record for domain of k.kozlowski@samsung.com designates 210.118.77.12 as permitted sender) smtp.mail=k.kozlowski@samsung.com Reply-To: rtc-linux@googlegroups.com Precedence: list Mailing-list: list rtc-linux@googlegroups.com; contact rtc-linux+owners@googlegroups.com List-ID: X-Google-Group-Id: 712029733259 List-Post: , List-Help: , List-Archive: Sender: rtc-linux@googlegroups.com List-Subscribe: , List-Unsubscribe: , This patch prepares for adding support for S2MPS14 RTC device to the rtc-s5m driver: 1. Adds a map of registers used by the driver which differ between the chipsets (S5M876X and S2MPS14). 2. Moves code of checking for alarm pending to separate function. Signed-off-by: Krzysztof Kozlowski Cc: Alessandro Zummo Cc: rtc-linux@googlegroups.com --- drivers/rtc/rtc-s5m.c | 157 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 48 deletions(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index b1627e9ab8f0..6a1290f8709a 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Samsung Electronics Co., Ltd + * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd * http://www.samsung.com * * Copyright (C) 2013 Google, Inc @@ -38,6 +38,42 @@ */ #define UDR_READ_RETRY_CNT 5 +/* Registers used by the driver which are different between chipsets. */ +struct s5m_rtc_reg_config { + /* Number of registers used for setting time/alarm0/alarm1 */ + unsigned int regs_count; + /* First register for time, seconds */ + unsigned int time; + /* RTC control register */ + unsigned int ctrl; + /* First register for alarm 0, seconds */ + unsigned int alarm0; + /* First register for alarm 1, seconds */ + unsigned int alarm1; + /* SMPL/WTSR register */ + unsigned int smpl_wtsr; + /* + * Register for update flag (UDR). Typically setting UDR field to 1 + * will enable update of time or alarm register. Then it will be + * auto-cleared after successful update. + */ + unsigned int rtc_udr_update; + /* Mask for UDR field in 'rtc_udr_update' register */ + unsigned int rtc_udr_mask; +}; + +/* Register map for S5M8763 and S5M8767 */ +static const struct s5m_rtc_reg_config s5m_rtc_regs = { + .regs_count = 8, + .time = S5M_RTC_SEC, + .ctrl = S5M_ALARM1_CONF, + .alarm0 = S5M_ALARM0_SEC, + .alarm1 = S5M_ALARM1_SEC, + .smpl_wtsr = S5M_WTSR_SMPL_CNTL, + .rtc_udr_update = S5M_RTC_UDR_CON, + .rtc_udr_mask = S5M_RTC_UDR_MASK, +}; + struct s5m_rtc_info { struct device *dev; struct sec_pmic_dev *s5m87xx; @@ -47,6 +83,7 @@ struct s5m_rtc_info { int device_type; int rtc_24hr_mode; bool wtsr_smpl; + const struct s5m_rtc_reg_config *regs; }; static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, @@ -104,8 +141,9 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) unsigned int data; do { - ret = regmap_read(info->regmap, S5M_RTC_UDR_CON, &data); - } while (--retry && (data & S5M_RTC_UDR_MASK) && !ret); + ret = regmap_read(info->regmap, info->regs->rtc_udr_update, + &data); + } while (--retry && (data & info->regs->rtc_udr_mask) && !ret); if (!retry) dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); @@ -113,21 +151,47 @@ static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) return ret; } +static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, + struct rtc_wkalrm *alarm) +{ + int ret; + unsigned int val; + + switch (info->device_type) { + case S5M8767X: + case S5M8763X: + ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); + val &= S5M_ALARM0_STATUS; + break; + default: + return -EINVAL; + } + if (ret < 0) + return ret; + + if (val) + alarm->pending = 1; + else + alarm->pending = 0; + + return 0; +} + static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) { int ret; unsigned int data; - ret = regmap_read(info->regmap, S5M_RTC_UDR_CON, &data); + ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); if (ret < 0) { dev_err(info->dev, "failed to read update reg(%d)\n", ret); return ret; } data |= S5M_RTC_TIME_EN_MASK; - data |= S5M_RTC_UDR_MASK; + data |= info->regs->rtc_udr_mask; - ret = regmap_write(info->regmap, S5M_RTC_UDR_CON, data); + ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); if (ret < 0) { dev_err(info->dev, "failed to write update reg(%d)\n", ret); return ret; @@ -143,7 +207,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) int ret; unsigned int data; - ret = regmap_read(info->regmap, S5M_RTC_UDR_CON, &data); + ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); if (ret < 0) { dev_err(info->dev, "%s: fail to read update reg(%d)\n", __func__, ret); @@ -151,9 +215,9 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) } data &= ~S5M_RTC_TIME_EN_MASK; - data |= S5M_RTC_UDR_MASK; + data |= info->regs->rtc_udr_mask; - ret = regmap_write(info->regmap, S5M_RTC_UDR_CON, data); + ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); if (ret < 0) { dev_err(info->dev, "%s: fail to write update reg(%d)\n", __func__, ret); @@ -200,10 +264,11 @@ static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data) static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); - u8 data[8]; + u8 data[info->regs->regs_count]; int ret; - ret = regmap_bulk_read(info->regmap, S5M_RTC_SEC, data, 8); + ret = regmap_bulk_read(info->regmap, info->regs->time, data, + info->regs->regs_count); if (ret < 0) return ret; @@ -230,7 +295,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); - u8 data[8]; + u8 data[info->regs->regs_count]; int ret = 0; switch (info->device_type) { @@ -251,7 +316,8 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); - ret = regmap_raw_write(info->regmap, S5M_RTC_SEC, data, 8); + ret = regmap_raw_write(info->regmap, info->regs->time, data, + info->regs->regs_count); if (ret < 0) return ret; @@ -263,11 +329,12 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); - u8 data[8]; + u8 data[info->regs->regs_count]; unsigned int val; int ret, i; - ret = regmap_bulk_read(info->regmap, S5M_ALARM0_SEC, data, 8); + ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); if (ret < 0) return ret; @@ -279,54 +346,42 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; alrm->enabled = !!val; - - ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); - if (ret < 0) - return ret; - break; case S5M8767X: s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, - alrm->time.tm_mday, alrm->time.tm_hour, - alrm->time.tm_min, alrm->time.tm_sec, - alrm->time.tm_wday); - alrm->enabled = 0; - for (i = 0; i < 7; i++) { + for (i = 0; i < info->regs->regs_count; i++) { if (data[i] & ALARM_ENABLE_MASK) { alrm->enabled = 1; break; } } - - alrm->pending = 0; - ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); - if (ret < 0) - return ret; break; default: return -EINVAL; } - if (val & S5M_ALARM0_STATUS) - alrm->pending = 1; - else - alrm->pending = 0; + dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, + alrm->time.tm_mday, alrm->time.tm_hour, + alrm->time.tm_min, alrm->time.tm_sec, + alrm->time.tm_wday); + + ret = s5m_check_peding_alarm_interrupt(info, alrm); return 0; } static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) { - u8 data[8]; + u8 data[info->regs->regs_count]; int ret, i; struct rtc_time tm; - ret = regmap_bulk_read(info->regmap, S5M_ALARM0_SEC, data, 8); + ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); if (ret < 0) return ret; @@ -341,10 +396,11 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) break; case S5M8767X: - for (i = 0; i < 7; i++) + for (i = 0; i < info->regs->regs_count; i++) data[i] &= ~ALARM_ENABLE_MASK; - ret = regmap_raw_write(info->regmap, S5M_ALARM0_SEC, data, 8); + ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); if (ret < 0) return ret; @@ -362,11 +418,12 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) { int ret; - u8 data[8]; + u8 data[info->regs->regs_count]; u8 alarm0_conf; struct rtc_time tm; - ret = regmap_bulk_read(info->regmap, S5M_ALARM0_SEC, data, 8); + ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); if (ret < 0) return ret; @@ -393,7 +450,8 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) if (data[RTC_YEAR1] & 0x7f) data[RTC_YEAR1] |= ALARM_ENABLE_MASK; - ret = regmap_raw_write(info->regmap, S5M_ALARM0_SEC, data, 8); + ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); if (ret < 0) return ret; ret = s5m8767_rtc_set_alarm_reg(info); @@ -410,7 +468,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); - u8 data[8]; + u8 data[info->regs->regs_count]; int ret; switch (info->device_type) { @@ -435,7 +493,8 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret < 0) return ret; - ret = regmap_raw_write(info->regmap, S5M_ALARM0_SEC, data, 8); + ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, + info->regs->regs_count); if (ret < 0) return ret; @@ -480,7 +539,7 @@ static const struct rtc_class_ops s5m_rtc_ops = { static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) { int ret; - ret = regmap_update_bits(info->regmap, S5M_WTSR_SMPL_CNTL, + ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, WTSR_ENABLE_MASK, enable ? WTSR_ENABLE_MASK : 0); if (ret < 0) @@ -491,7 +550,7 @@ static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) { int ret; - ret = regmap_update_bits(info->regmap, S5M_WTSR_SMPL_CNTL, + ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, SMPL_ENABLE_MASK, enable ? SMPL_ENABLE_MASK : 0); if (ret < 0) @@ -545,11 +604,13 @@ static int s5m_rtc_probe(struct platform_device *pdev) case S5M8763X: info->irq = regmap_irq_get_virq(s5m87xx->irq_data, S5M8763_IRQ_ALARM0); + info->regs = &s5m_rtc_regs; break; case S5M8767X: info->irq = regmap_irq_get_virq(s5m87xx->irq_data, S5M8767_IRQ_RTCA1); + info->regs = &s5m_rtc_regs; break; default: @@ -593,7 +654,7 @@ static void s5m_rtc_shutdown(struct platform_device *pdev) if (info->wtsr_smpl) { for (i = 0; i < 3; i++) { s5m_rtc_enable_wtsr(info, false); - regmap_read(info->regmap, S5M_WTSR_SMPL_CNTL, &val); + regmap_read(info->regmap, info->regs->smpl_wtsr, &val); pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); if (val & WTSR_ENABLE_MASK) pr_emerg("%s: fail to disable WTSR\n",