From patchwork Wed Oct 20 09:50:48 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lan Chunhe-B25806 X-Patchwork-Id: 68416 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-ww0-f56.google.com (mail-ww0-f56.google.com [74.125.82.56]) by ozlabs.org (Postfix) with ESMTP id 50368B6EFF for ; Wed, 20 Oct 2010 20:49:18 +1100 (EST) Received: by wwi14 with SMTP id 14sf352965wwi.11 for ; Wed, 20 Oct 2010 02:49:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=beta; h=domainkey-signature:received:x-beenthere:received:received:received :received:received-spf:received:received:x-spamscore:x-bigfish :x-spam-tcs-scl:received:received:received:received:received :received:from:to:cc:subject:date:message-id:x-mailer :x-originalarrivaltime:mime-version:x-reverse-dns: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=1fyIHhWf+eW83WDZiLBYUI7fhjgxad/n9FHBjR4jei0=; b=NhKfFVnrWBorb/l5/Zx2YoSuIeIZXpWLIZPw1SNeOXnBXkA8Q28ioqgxKiNOdLI7dq A9NIeI+5Sjn8wV7cptLTh0VWVfuEkEx3s5bbh74RAqUixpkC70R/NHUVnz7025na3Cb3 uUYElZoHJMzNfAgsPhXr2CLIvqNEHRVZWDMqs= DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlegroups.com; s=beta; h=x-beenthere:received-spf:x-spamscore:x-bigfish:x-spam-tcs-scl:from :to:cc:subject:date:message-id:x-mailer:x-originalarrivaltime :mime-version:x-reverse-dns: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; b=CerFsSlN0C/TWwL7chBiyqpOCSqWvgIOrts8aC0QEBRAaR3Y5QlY9/kRjPwzFIAurJ 048I3xx/bkvZ2biHYa5wdaq0ejZSU2ICi6CJvm8fwgmnx66NSMCdklVXhz/B2OnyXBBJ wTd2o8k/4ccq03Gz8wPQZehjjRvVpgfx/zvjI= Received: by 10.216.82.142 with SMTP id o14mr969739wee.27.1287568155573; Wed, 20 Oct 2010 02:49:15 -0700 (PDT) X-BeenThere: rtc-linux@googlegroups.com Received: by 10.227.168.134 with SMTP id u6ls451381wby.1.p; Wed, 20 Oct 2010 02:49:14 -0700 (PDT) Received: by 10.227.69.195 with SMTP id a3mr275162wbj.27.1287568154765; Wed, 20 Oct 2010 02:49:14 -0700 (PDT) Received: by 10.227.69.195 with SMTP id a3mr275161wbj.27.1287568154740; Wed, 20 Oct 2010 02:49:14 -0700 (PDT) Received: from DB3EHSOBE001.bigfish.com (db3ehsobe001.messaging.microsoft.com [213.199.154.139]) by gmr-mx.google.com with ESMTP id x80si4283256weq.4.2010.10.20.02.49.14; Wed, 20 Oct 2010 02:49:14 -0700 (PDT) Received-SPF: neutral (google.com: 213.199.154.139 is neither permitted nor denied by best guess record for domain of B25806@freescale.com) client-ip=213.199.154.139; Received: from mail21-db3-R.bigfish.com (10.3.81.242) by DB3EHSOBE001.bigfish.com (10.3.84.21) with Microsoft SMTP Server id 14.1.225.8; Wed, 20 Oct 2010 09:49:02 +0000 Received: from mail21-db3 (localhost.localdomain [127.0.0.1]) by mail21-db3-R.bigfish.com (Postfix) with ESMTP id 0F32AB08461 for ; Wed, 20 Oct 2010 09:49:02 +0000 (UTC) X-SpamScore: 3 X-BigFish: VS3(zzc8kzz1202hzz8275bhz2dh2a8h62h) X-Spam-TCS-SCL: 1:0 Received: from mail21-db3 (localhost.localdomain [127.0.0.1]) by mail21-db3 (MessageSwitch) id 1287568141453047_30395; Wed, 20 Oct 2010 09:49:01 +0000 (UTC) Received: from DB3EHSMHS012.bigfish.com (unknown [10.3.81.241]) by mail21-db3.bigfish.com (Postfix) with ESMTP id 6B851348050 for ; Wed, 20 Oct 2010 09:49:01 +0000 (UTC) Received: from az33egw02.freescale.net (192.88.158.103) by DB3EHSMHS012.bigfish.com (10.3.87.112) with Microsoft SMTP Server (TLS) id 14.0.482.44; Wed, 20 Oct 2010 09:49:00 +0000 Received: from az33smr01.freescale.net (az33smr01.freescale.net [10.64.34.199]) by az33egw02.freescale.net (8.14.3/8.14.3) with ESMTP id o9K9mw0I016664 for ; Wed, 20 Oct 2010 02:48:58 -0700 (MST) Received: from zch01exm28.fsl.freescale.net (zch01exm28.ap.freescale.net [10.192.129.225]) by az33smr01.freescale.net (8.13.1/8.13.0) with ESMTP id o9K9mvgK007921 for ; Wed, 20 Oct 2010 04:48:58 -0500 (CDT) Received: from localhost.localdomain ([10.193.20.71]) by zch01exm28.fsl.freescale.net with Microsoft SMTPSVC(6.0.3790.4675); Wed, 20 Oct 2010 17:49:16 +0800 From: Lan Chunhe-B25806 To: CC: , , , Lan Chunhe-B25806 Subject: [rtc-linux] [PATCH v2] Add the alarm function for driver of DS3232 RTC Date: Wed, 20 Oct 2010 17:50:48 +0800 Message-ID: <1287568248-16693-1-git-send-email-b25806@freescale.com> X-Mailer: git-send-email 1.5.4.5 X-OriginalArrivalTime: 20 Oct 2010 09:49:16.0814 (UTC) FILETIME=[0F5AAAE0:01CB703C] MIME-Version: 1.0 X-Reverse-DNS: az33egw02.freescale.net X-Original-Sender: b25806@freescale.com X-Original-Authentication-Results: gmr-mx.google.com; spf=neutral (google.com: 213.199.154.139 is neither permitted nor denied by best guess record for domain of B25806@freescale.com) smtp.mail=B25806@freescale.com Reply-To: rtc-linux@googlegroups.com Precedence: list Mailing-list: list rtc-linux@googlegroups.com; contact rtc-linux+owners@googlegroups.com List-ID: List-Post: , List-Help: , List-Archive: Sender: rtc-linux@googlegroups.com List-Subscribe: , List-Unsubscribe: , The former driver of DS3232 RTC only has the tick function, and now add the alarm function for driver of DS3232 RTC. So, the driver of DS3232 RTC is complete. Signed-off-by: Lan Chunhe-B25806 --- drivers/rtc/Kconfig | 3 +- drivers/rtc/rtc-ds3232.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 48ca713..ac4a9cb 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -171,7 +171,8 @@ config RTC_DRV_DS3232 depends on RTC_CLASS && I2C help If you say yes here you get support for Dallas Semiconductor - DS3232 real-time clock chips. + DS3232 real-time clock chips. If an interrupt is associated + with the device, the alarm functionality is supported. This driver can also be built as a module. If so, the module will be called rtc-ds3232. diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 9de8516..5706355 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -2,6 +2,7 @@ * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C * * Copyright (C) 2009-2010 Freescale Semiconductor. + * Author: Jack Lan * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -175,6 +176,182 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) DS3232_REG_SECONDS, 7, buf); } +/* + * DS3232 has two alarm, we only use alarm1 + * According to linux specification, only support one-shot alarm + * no periodic alarm mode + */ +static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control, stat; + int ret; + u8 buf[4]; + + mutex_lock(&ds3232->mutex); + + ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); + if (ret < 0) + goto out; + stat = ret; + ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (ret < 0) + goto out; + control = ret; + ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto out; + + alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F); + alarm->time.tm_min = bcd2bin(buf[1] & 0x7F); + alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F); + alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F); + + alarm->time.tm_mon = -1; + alarm->time.tm_year = -1; + alarm->time.tm_wday = -1; + alarm->time.tm_yday = -1; + alarm->time.tm_isdst = -1; + + alarm->enabled = !!(control & DS3232_REG_CR_A1IE); + alarm->pending = !!(stat & DS3232_REG_SR_A1F); + + ret = 0; +out: + mutex_unlock(&ds3232->mutex); + return ret; +} + +/* + * linux rtc-module does not support wday alarm + * and only 24h time mode supported indeed + */ +static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control, stat; + int ret; + u8 buf[4]; + + if (client->irq <= 0) + return -EINVAL; + + mutex_lock(&ds3232->mutex); + + buf[0] = bin2bcd(alarm->time.tm_sec); + buf[1] = bin2bcd(alarm->time.tm_min); + buf[2] = bin2bcd(alarm->time.tm_hour); + buf[3] = bin2bcd(alarm->time.tm_mday); + + /* clear alarm interrupt enable bit */ + ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (ret < 0) + goto out; + control = ret; + control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); + ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + if (ret < 0) + goto out; + + /* clear any pending alarm flag */ + ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); + if (ret < 0) + goto out; + stat = ret; + stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); + ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + if (ret < 0) + goto out; + + ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + + if (alarm->enabled) { + control |= DS3232_REG_CR_A1IE; + ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + } +out: + mutex_unlock(&ds3232->mutex); + return ret; +} + +static void ds3232_update_alarm(struct i2c_client *client) +{ + struct ds3232 *ds3232 = i2c_get_clientdata(client); + int control; + int ret; + u8 buf[4]; + + mutex_lock(&ds3232->mutex); + + ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto unlock; + + buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[0]; + buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[1]; + buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[2]; + buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? + 0x80 : buf[3]; + + ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); + if (ret < 0) + goto unlock; + + control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); + if (control < 0) + goto unlock; + + if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) + /* enable alarm1 interrupt */ + control |= DS3232_REG_CR_A1IE; + else + /* disable alarm1 interrupt */ + control &= ~(DS3232_REG_CR_A1IE); + i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); + +unlock: + mutex_unlock(&ds3232->mutex); +} + +static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + + if (client->irq <= 0) + return -EINVAL; + + if (enabled) + ds3232->rtc->irq_data |= RTC_AF; + else + ds3232->rtc->irq_data &= ~RTC_AF; + + ds3232_update_alarm(client); + return 0; +} + +static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds3232 *ds3232 = i2c_get_clientdata(client); + + if (client->irq <= 0) + return -EINVAL; + + if (enabled) + ds3232->rtc->irq_data |= RTC_UF; + else + ds3232->rtc->irq_data &= ~RTC_UF; + + ds3232_update_alarm(client); + return 0; +} + static irqreturn_t ds3232_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; @@ -222,6 +399,10 @@ unlock: static const struct rtc_class_ops ds3232_rtc_ops = { .read_time = ds3232_read_time, .set_time = ds3232_set_time, + .read_alarm = ds3232_read_alarm, + .set_alarm = ds3232_set_alarm, + .alarm_irq_enable = ds3232_alarm_irq_enable, + .update_irq_enable = ds3232_update_irq_enable, }; static int __devinit ds3232_probe(struct i2c_client *client,