From patchwork Fri Feb 28 13:00:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 325181 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-ie0-x239.google.com (mail-ie0-x239.google.com [IPv6:2607:f8b0:4001:c03::239]) (using TLSv1 with cipher ECDHE-RSA-RC4-SHA (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 191C52C00AB for ; Sat, 1 Mar 2014 00:00:22 +1100 (EST) Received: by mail-ie0-f185.google.com with SMTP id tp5sf3607ieb.2 for ; Fri, 28 Feb 2014 05:00:20 -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=wcQPwHqbuL6Eko3Ml/plwnHnTstgbq1XWnEiw4pkvr4=; b=MQ02HXpCPevTzLp4VUh/E2/YTtmCbmHw++ODAbINC3HP4GmRRaiq/IQrk4aEUkLMH+ a3snE+NLl5y5olCnR/W5GP6Zom5ZBjN0LhBSKvr1WO5RUoTRnhxHBB/3FhrwrVeTiCf7 us+ZvTzViywjzaLLwMpUo+eIEJiPsArJ6RSBU5ysHezzc5jW8jgFXqNIDMs+9uTyrTcr hpg9SDipI3E7S3p6ks/poLC84QSJ8vxunKz3Zpq+rbpb7Hnvgrz2l+FqecYh+aZOWWeh l18VYkw6GQMnzqSQH89Ext0+wh0lfnMEv775gZaTwYNgCfyxBTWy0jy5JH+U1fdmbQQq 8mwg== X-Received: by 10.140.107.138 with SMTP id h10mr45332qgf.2.1393592419776; Fri, 28 Feb 2014 05:00:19 -0800 (PST) MIME-Version: 1.0 X-BeenThere: rtc-linux@googlegroups.com Received: by 10.140.23.175 with SMTP id 44ls1136024qgp.12.gmail; Fri, 28 Feb 2014 05:00:19 -0800 (PST) X-Received: by 10.58.152.228 with SMTP id vb4mr1183032veb.0.1393592419197; Fri, 28 Feb 2014 05:00:19 -0800 (PST) Received: from mailout2.w1.samsung.com (mailout2.w1.samsung.com. [210.118.77.12]) by gmr-mx.google.com with ESMTPS id ox2si551467pbc.1.2014.02.28.05.00.18 for (version=TLSv1 cipher=RC4-MD5 bits=128/128); Fri, 28 Feb 2014 05:00:19 -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 eucpsbgm2.samsung.com (unknown [203.254.199.245]) 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 <0N1P00H5NISDYH70@mailout2.w1.samsung.com> for rtc-linux@googlegroups.com; Fri, 28 Feb 2014 13:00:13 +0000 (GMT) X-AuditID: cbfec7f5-b7fc96d000004885-a0-53108862bab3 Received: from eusync3.samsung.com ( [203.254.199.213]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id B6.E8.18565.26880135; Fri, 28 Feb 2014 13:00:18 +0000 (GMT) Received: from AMDC1943.digital.local ([106.116.151.171]) by eusync3.samsung.com (Oracle Communications Messaging Server 7u4-23.01(7.0.4.23.0) 64bit (built Aug 10 2011)) with ESMTPA id <0N1P00APRISCCQ20@eusync3.samsung.com>; Fri, 28 Feb 2014 13:00:18 +0000 (GMT) From: Krzysztof Kozlowski To: Sangbeom Kim , Samuel Ortiz , Lee Jones , Alessandro Zummo , linux-kernel@vger.kernel.org, rtc-linux@googlegroups.com Cc: Kyungmin Park , Marek Szyprowski , Bartlomiej Zolnierkiewicz , Tomasz Figa , Krzysztof Kozlowski Subject: [rtc-linux] [PATCH 4/5] rtc: s5m: Support different register layout Date: Fri, 28 Feb 2014 14:00:07 +0100 Message-id: <1393592408-27181-5-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1393592408-27181-1-git-send-email-k.kozlowski@samsung.com> References: <1393592408-27181-1-git-send-email-k.kozlowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFuphluLIzCtJLcpLzFFi42I5/e/4Vd2kDoFgg2cLWSyWXLzKbrFxxnpW i9cvDC3ONr1ht7j/9SijxeVdc9gs1h65y26xv7OD0eJ0N6vFxRVfmCzWz3jN4sDtsWfiSTaP O9f2sHnMOxno0bdlFaPH9Hk/mTw+b5ILYIvisklJzcksSy3St0vgymiZ8YClYENMxcMj/9kb GFd5dTFyckgImEi8aZvIDmGLSVy4t56ti5GLQ0hgKaPE8U1drBBOH5PE2vsNTCBVbALGEpuX LwGrEhG4yigxcclisHZmgeeMEk+/h4PYwgIOEut3LwOLswioShx+fYwNxOYVcJdY/mEzSxcj B9A6BYk5k2xAwpwCHhInn09hBbGFgErurd7KPIGRdwEjwypG0dTS5ILipPRcI73ixNzi0rx0 veT83E2MkBD8uoNx6TGrQ4wCHIxKPLwTPPmDhVgTy4orcw8xSnAwK4nwPmkSCBbiTUmsrEot yo8vKs1JLT7EyMTBKdXA2Hutyy9CaHOcw4kD6gf1duXtPHrFJcJ7UWh9kmJM2ZJEtvdi1qGR Hz+naOoYPqmQ+79iot9fc+GPIZraz+6ULK9suPot/27Dk2+fG3fGrJv6ZO/TzmW874q/xUw9 HGtfzWnokdJkYM02w6nbfY7m2xPxCm9fdC7sCzU0dJxbszXYueXXWw4eJZbijERDLeai4kQA otNhnh8CAAA= 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 --- 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 109d57800157..b3394b881cad 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) @@ -552,11 +611,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: @@ -600,7 +661,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",