From patchwork Fri Oct 2 09:17:21 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= X-Patchwork-Id: 525429 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail-lb0-x23c.google.com (mail-lb0-x23c.google.com [IPv6:2a00:1450:4010:c04::23c]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id C706F1402D5 for ; Fri, 2 Oct 2015 19:17:50 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.b=I/JEGGQI; dkim-atps=neutral Received: by lbcao8 with SMTP id ao8sf10080053lbc.1 for ; Fri, 02 Oct 2015 02:17:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20120806; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding :x-original-sender:x-original-authentication-results:reply-to :precedence:mailing-list:list-id:x-spam-checked-in-group:list-post :list-help:list-archive:sender:list-subscribe:list-unsubscribe; bh=gNhS0ZukT1KU/FiLZbBdCBYnutgOZrktHOF0RNy4Gcs=; b=I/JEGGQIy5gS6iEYvW8epvjpHaHHkpLDwkoSGByww4ogMBi20yzL+6CXnFbU4vRUUZ 0P3yjFuImlpfwIwqEuU8aJuTsK3zSW3FEZVs6m/J4nt+0knVyCd7/HHFtu7wqae+VXGi XeNyop+nVr1PXmi8ahvT159++2/cbZpU/xzfHUdDf6eGS2SudcI7TP1aY/XnWMb52PiD avF1IUfwaPSh/RrIRZc4sTFGYasu1eIo4jrxtDKSxLzuznlb39G3XuoceeivIo1phJKb +iSwDBp7/kDNW95ksOcEuWWPAJeeOCM2H9GzLta3jUPJN6WUInuj2clMrkQgMTCP5T31 isCg== X-Received: by 10.25.82.1 with SMTP id g1mr52522lfb.33.1443777467796; Fri, 02 Oct 2015 02:17:47 -0700 (PDT) X-BeenThere: rtc-linux@googlegroups.com Received: by 10.25.21.96 with SMTP id l93ls211327lfi.20.gmail; Fri, 02 Oct 2015 02:17:47 -0700 (PDT) X-Received: by 10.112.138.170 with SMTP id qr10mr2412000lbb.4.1443777467367; Fri, 02 Oct 2015 02:17:47 -0700 (PDT) Received: from metis.ext.pengutronix.de (metis.ext.pengutronix.de. [2001:67c:670:201:290:27ff:fe1d:cc33]) by gmr-mx.google.com with ESMTPS id c1si202403wiv.3.2015.10.02.02.17.47 for (version=TLS1_2 cipher=AES128-SHA256 bits=128/128); Fri, 02 Oct 2015 02:17:47 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of ukl@pengutronix.de designates 2001:67c:670:201:290:27ff:fe1d:cc33 as permitted sender) client-ip=2001:67c:670:201:290:27ff:fe1d:cc33; Received: from dude.hi.pengutronix.de ([2001:67c:670:100:1d::7]) by metis.ext.pengutronix.de with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from ) id 1ZhwT4-0001P2-9S; Fri, 02 Oct 2015 11:17:30 +0200 Received: from ukl by dude.hi.pengutronix.de with local (Exim 4.86) (envelope-from ) id 1ZhwT2-0004DE-Vd; Fri, 02 Oct 2015 11:17:28 +0200 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= To: Alexandre Belloni Cc: Alessandro Zummo , rtc-linux@googlegroups.com, kernel@pengutronix.de, Greg Kroah-Hartman , linux-kernel@vger.kernel.org Subject: [rtc-linux] [PATCH v1 3/4 RFC] rtc: pcf2127: implement reading battery status bits Date: Fri, 2 Oct 2015 11:17:21 +0200 Message-Id: <1443777442-15920-4-git-send-email-u.kleine-koenig@pengutronix.de> X-Mailer: git-send-email 2.6.0 In-Reply-To: <1443777442-15920-1-git-send-email-u.kleine-koenig@pengutronix.de> References: <1443777442-15920-1-git-send-email-u.kleine-koenig@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::7 X-SA-Exim-Mail-From: ukl@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: rtc-linux@googlegroups.com X-Original-Sender: u.kleine-koenig@pengutronix.de X-Original-Authentication-Results: gmr-mx.google.com; spf=pass (google.com: best guess record for domain of ukl@pengutronix.de designates 2001:67c:670:201:290:27ff:fe1d:cc33 as permitted sender) smtp.mailfrom=ukl@pengutronix.de Reply-To: rtc-linux@googlegroups.com Precedence: list Mailing-list: list rtc-linux@googlegroups.com; contact rtc-linux+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: rtc-linux@googlegroups.com X-Google-Group-Id: 712029733259 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , The rtc features a battery switch-over function. Export battery status and if a switch-over occured via sysfs. Signed-off-by: Uwe Kleine-König --- Notes: Note this patch is wrong, don't merge! Calling sysfs_create_files in the driver's probe is too late. I didn't find a nice alternative though. But in case someone feels like pointing me in the right direction or using this even with this being wrong, here comes the patch anyhow. drivers/rtc/rtc-pcf2127.c | 132 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 7eb6ff26185e..db057db88031 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -22,7 +22,11 @@ #define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */ #define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */ + #define PCF2127_REG_CTRL3 (0x02) /* Control Register 3 */ +#define PCF2127_REG_CTRL3_BF 0x08 +#define PCF2127_REG_CTRL3_BLF 0x04 + #define PCF2127_REG_SC (0x03) /* datetime */ #define PCF2127_REG_MN (0x04) #define PCF2127_REG_HR (0x05) @@ -54,7 +58,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } - if (buf[PCF2127_REG_CTRL3] & 0x04) + if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF) dev_info(&client->dev, "low voltage detected, check/replace RTC battery.\n"); @@ -186,10 +190,116 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { .set_time = pcf2127_rtc_set_time, }; +struct pcf2127_bitattr { + struct device_attribute attr; + unsigned bitmask; +}; + +static ssize_t pcf2127_bitattr_clear(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned char i2cbuf[2] = { PCF2127_REG_CTRL3, }; + struct pcf2127_bitattr *bitattr = + container_of(attr, struct pcf2127_bitattr, attr); + int ret; + long val; + + if (!count) + return 0; + + ret = kstrtol(buf, 0, &val); + if (ret) + return ret; + + /* we only accept writing 0 */ + if (val != 0) + return -EINVAL; + + ret = i2c_master_send(client, i2cbuf, 1); + if (!ret) + ret = -EIO; + if (ret < 0) + return ret; + + ret = i2c_master_recv(client, i2cbuf + 1, 1); + if (!ret) + ret = -EIO; + if (ret < 0) + return ret; + + i2cbuf[1] &= ~bitattr->bitmask; + + ret = i2c_master_send(client, i2cbuf, 2); + if (!ret) + ret = -EIO; + if (ret < 0) + return ret; + + return count; +} + +static ssize_t pcf2127_bitattr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned char reg = PCF2127_REG_CTRL3; + struct pcf2127_bitattr *bitattr = + container_of(attr, struct pcf2127_bitattr, attr); + int ret; + + ret = i2c_master_send(client, ®, 1); + if (!ret) + ret = -EIO; + if (ret < 0) + return ret; + + ret = i2c_master_recv(client, ®, 1); + if (!ret) + ret = -EIO; + if (ret < 0) + return ret; + + return scnprintf(buf, PAGE_SIZE, + "%d\n", !!(reg & bitattr->bitmask)); +} + +static struct pcf2127_bitattr pcf2127_battery_low = { + .attr = { + .attr = { + .name = "battery_low", + .mode = S_IRUGO, + }, + .show = pcf2127_bitattr_show, + }, + .bitmask = PCF2127_REG_CTRL3_BLF, +}; + +static struct pcf2127_bitattr pcf2127_battery_switch_over = { + .attr = { + .attr = { + .name = "battery_switch_over", + .mode = S_IWUSR | S_IRUGO, + }, + .show = pcf2127_bitattr_show, + .store = pcf2127_bitattr_clear, + }, + .bitmask = PCF2127_REG_CTRL3_BF, +}; + +static const struct attribute *pcf2127_attributes[] = { + &pcf2127_battery_low.attr.attr, + &pcf2127_battery_switch_over.attr.attr, + NULL +}; + static int pcf2127_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pcf2127 *pcf2127; + int ret; dev_dbg(&client->dev, "%s\n", __func__); @@ -203,11 +313,28 @@ static int pcf2127_probe(struct i2c_client *client, i2c_set_clientdata(client, pcf2127); + ret = sysfs_create_files(&client->dev.kobj, pcf2127_attributes); + if (ret < 0) { + dev_err(&client->dev, "failed to register sysfs attributes\n"); + return ret; + } + pcf2127->rtc = devm_rtc_device_register(&client->dev, pcf2127_driver.driver.name, &pcf2127_rtc_ops, THIS_MODULE); - return PTR_ERR_OR_ZERO(pcf2127->rtc); + if (IS_ERR(pcf2127->rtc)) { + ret = PTR_ERR(pcf2127->rtc); + sysfs_remove_files(&client->dev.kobj, pcf2127_attributes); + } + + return ret; +} + +static int pcf2127_remove(struct i2c_client *client) +{ + sysfs_remove_files(&client->dev.kobj, pcf2127_attributes); + return 0; } static const struct i2c_device_id pcf2127_id[] = { @@ -231,6 +358,7 @@ static struct i2c_driver pcf2127_driver = { .of_match_table = of_match_ptr(pcf2127_of_match), }, .probe = pcf2127_probe, + .remove = pcf2127_remove, .id_table = pcf2127_id, };