Received: by 10.223.176.46 with SMTP id f43csp4516794wra; Tue, 23 Jan 2018 10:23:39 -0800 (PST) X-Google-Smtp-Source: AH8x225ncCI4v0GJnnfJLcg85WKbxeYc/YlWCwqVxlvGnFKPuhp1wL4J1nGJZdfD0nyPthVc+JKQ X-Received: by 10.202.173.194 with SMTP id w185mr6279797oie.273.1516731819733; Tue, 23 Jan 2018 10:23:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516731819; cv=none; d=google.com; s=arc-20160816; b=soQ01rXCTdhD62fHPV+dsXV60QeiS6fdrQzxu/FZJ36sjcfV4wsaDg7UTXn7JG2rD9 TNdGVO+Lr9RKgdEWSxPsvaSQkxoKlA7F0jhJG2hB62lactK/QH1gTzYHrPeadv6PuRV+ yYbzeFqOj9+SX92rVVSb7i9w+VZpDc3q0yxTfWkRjvWl5eILzdYMEpTP4dMrx6JPlbfz 0T2h/p0ITIijsBFwG2B+4cIAhfEsAkvvWFjTF6oz3YeYtmvxtAP/OQbRSL8i6CDa7zVd xgpoX5WqiFNaYPnCVZcXvDFy2QhVe3TVSkROfNuDcZAXVN/UR75rNV50EIdlZj/p9XWq LiZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date:dkim-signature:arc-authentication-results; bh=47tZYsR1HV7rLq4y15fyS3DsNrSF31d7ZnnIs3U64NM=; b=vaynrnNZQcZ/6s57ONvY8MC99JOVc911T7PhIBzqcqdPNI70URj/x7ir0UZWzScsuQ 573oWpJg12CiHL2HJ9PSOy+lzIp43VjVYohUJd+N/vCAC2CF358B7KDvG3L2jtbIPZvp 9aaQANr3LpJEPPpAMNbg7Ui/9wSp7CjUddCkhLRwINCp5vN4W6gm1aBqJB6AizqVP+z1 nCH74ftQ2SGmyYjFahk67pY1/6S2jF0Ve9m/dWVwoE51qGyVSQ4QcQ0qaBJ7LrPvS2Lg 8YXEfntse90H1k2nafNZQSVI977B49wjOVknLNYH23ufMibBb+OqoiSaCXVDUiyOZAue MVSg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=dGYq3LWf; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o133si8616477itd.110.2018.01.23.10.23.26; Tue, 23 Jan 2018 10:23:39 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20161025 header.b=dGYq3LWf; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752082AbeAWSXA (ORCPT + 99 others); Tue, 23 Jan 2018 13:23:00 -0500 Received: from mail-pg0-f68.google.com ([74.125.83.68]:38364 "EHLO mail-pg0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751547AbeAWSW5 (ORCPT ); Tue, 23 Jan 2018 13:22:57 -0500 Received: by mail-pg0-f68.google.com with SMTP id y27so844888pgc.5; Tue, 23 Jan 2018 10:22:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=47tZYsR1HV7rLq4y15fyS3DsNrSF31d7ZnnIs3U64NM=; b=dGYq3LWfZC23pF+G26J5nihOf0Q5y1/JJ+r2ISd6XaBqHCDw3llG37YMVcVauYhYRk bAOcfwRqMZ3HI/Kb3f1qCUNE6rnEHiqg/Zh1q2I5mc1RipSk/c5OOD1xf9+8wPvxURMM yk7iFl66TrI+4AL0czQHvU/xSUPTCGUuO+rBa9uBtX3ZdbuElKzJNxYokFowwr3qWxfO pMDD//YC522ofz6oe7kKQlCBGylbTP+4bY1xjO5mbgbI0IF4VU7Gbg5VWTIEtZNJei7W SzJ9/hS+nXhUHgT5DGns6Al/bQyxuFHynl7uHSPXKRHPSq3z13D0WvYMhG1q72/MCkj5 1ryg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :references:mime-version:content-disposition:in-reply-to:user-agent; bh=47tZYsR1HV7rLq4y15fyS3DsNrSF31d7ZnnIs3U64NM=; b=VwQ08tdtSKflf7hQU4FroPZ6bBvMOfbJy5flgnSX4n37VQGuaGZXaW1l4khvyC/3Ic QbM9jExJfzywtCQLnmNXX84q1DPlZsTFj+bAMMuPZtlE4z6qQ7Wd2VwnBUzZPAGI4gjE xF/P5KnAF1qZimrYpgL+9QXTRlaCjew6TqDzjt4BSDePKsTLfpae3zUK9epW9bBoD4K9 Eg19+leZV/ivZ3dNy+lNsWmGXEVrX2GEoP5vXSJXFHOpJpSm3LlQVtuCDqtnz04KlwPz ZS1XK4GvTL7Sfqo26LdM22zgUi6agYIoWnNEAZ2p7bvjq4xYe8zQXjIWrG7uCv5X+W3E DpYQ== X-Gm-Message-State: AKwxyteL6V2hEaW7G3MF/uP2QeBA5aeFkwtmH78SqiUU6nHkQ6t2X+KY Ee0AuXFMzYgApa/ZksuBtGCQfg== X-Received: by 2002:a17:902:14d:: with SMTP id 71-v6mr6187647plb.42.1516731777080; Tue, 23 Jan 2018 10:22:57 -0800 (PST) Received: from localhost (108-223-40-66.lightspeed.sntcca.sbcglobal.net. [108.223.40.66]) by smtp.gmail.com with ESMTPSA id 9sm7775155pfq.62.2018.01.23.10.22.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 23 Jan 2018 10:22:56 -0800 (PST) Date: Tue, 23 Jan 2018 10:22:54 -0800 From: Guenter Roeck To: Michael Grzeschik Cc: a.zummo@towertech.it, alexandre.belloni@free-electrons.com, linux-rtc@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, jdelvare@suse.com, kernel@pengutronix.de, Denis.Osterland@diehl.com Subject: Re: [PATCH 4/4] rtc: isl1208: add support for isl1219 with hwmon for tamper detection Message-ID: <20180123182254.GA27379@roeck-us.net> References: <20180123121801.4214-1-m.grzeschik@pengutronix.de> <20180123121801.4214-5-m.grzeschik@pengutronix.de> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180123121801.4214-5-m.grzeschik@pengutronix.de> User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Jan 23, 2018 at 01:18:01PM +0100, Michael Grzeschik wrote: > We add support for the ISL1219 chip that got an integrated tamper > detection function. This patch implements the feature by using an hwmon > interface. > > The ISL1219 can also describe the timestamp of the intrusion > event. For this we add the documentation of the new interface > intrusion[0-*]_timestamp. > > The devicetree documentation for the ISL1219 device tree > binding is added with an short example. > > Signed-off-by: Michael Grzeschik > Signed-off-by: Denis Osterland > --- > .../rtc/{intersil,isl1208.txt => isil,isl1208.txt} | 18 +- > Documentation/hwmon/sysfs-interface | 7 + > drivers/rtc/rtc-isl1208.c | 190 +++++++++++++++++++-- > 3 files changed, 201 insertions(+), 14 deletions(-) > rename Documentation/devicetree/bindings/rtc/{intersil,isl1208.txt => isil,isl1208.txt} (57%) > > diff --git a/Documentation/devicetree/bindings/rtc/intersil,isl1208.txt b/Documentation/devicetree/bindings/rtc/isil,isl1208.txt > similarity index 57% > rename from Documentation/devicetree/bindings/rtc/intersil,isl1208.txt > rename to Documentation/devicetree/bindings/rtc/isil,isl1208.txt > index a54e99feae1ca..d549699e1cfc4 100644 > --- a/Documentation/devicetree/bindings/rtc/intersil,isl1208.txt > +++ b/Documentation/devicetree/bindings/rtc/isil,isl1208.txt > @@ -1,14 +1,21 @@ > -Intersil ISL1208, ISL1218 I2C RTC/Alarm chip > +Intersil ISL1208, ISL1218, ISL1219 I2C RTC/Alarm chip > > ISL1208 is a trivial I2C device (it has simple device tree bindings, > consisting of a compatible field, an address and possibly an interrupt > line). > > +ISL1219 supports tamper detection user space representation through > +case intrusion hwmon sensor. > +ISL1219 has additional pins EVIN and #EVDET for tamper detection. > +I2C devices support only one irq. #IRQ and #EVDET are open-drain active low, > +so it is possible layout them to one SoC pin with pull-up. > + > Required properties supported by the device: > > - "compatible": must be one of > "isil,isl1208" > "isil,isl1218" > + "isil,isl1219" > - "reg": I2C bus address of the device > > Optional properties: > @@ -33,3 +40,12 @@ Example isl1208 node with #IRQ pin connected to SoC gpio1 pin 12: > interrupt-parent = <&gpio1>; > interrupts = <12 IRQ_TYPE_EDGE_FALLING>; > }; > + > +Example isl1219 node with #IRQ pin and #EVDET pin connected to SoC gpio1 pin 12: > + > + isl1219: isl1219@68 { > + compatible = "intersil,isl1219"; > + reg = <0x68>; > + interrupts-extended = <&gpio1 12 IRQ_TYPE_EDGE_FALLING>; > + }; > + > diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface > index fc337c317c673..a12b3c2b2a18c 100644 > --- a/Documentation/hwmon/sysfs-interface > +++ b/Documentation/hwmon/sysfs-interface > @@ -702,6 +702,13 @@ intrusion[0-*]_alarm > the user. This is done by writing 0 to the file. Writing > other values is unsupported. > > +intrusion[0-*]_timestamp > + Chassis intrusion detection > + YYYY-MM-DD HH:MM:SS UTC (ts.sec): intrusion detected > + RO > + The corresponding timestamp on which the intrustion > + was detected. > + Sneaky. Nack. You don't just add attributes to the ABI because you want it, without serious discussion, and much less so hidden in an RTC driver (and even less as unparseable attribute). In addition to that, I consider the attribute unnecessary. The intrusion already generates an event which should be sufficient for all practical purposes. Guenter > intrusion[0-*]_beep > Chassis intrusion beep > 0: disable > diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c > index a13a4ba79004d..6e4d24614d98b 100644 > --- a/drivers/rtc/rtc-isl1208.c > +++ b/drivers/rtc/rtc-isl1208.c > @@ -14,6 +14,8 @@ > #include > #include > #include > +#include > +#include > > /* Register map */ > /* rtc section */ > @@ -33,6 +35,7 @@ > #define ISL1208_REG_SR_ARST (1<<7) /* auto reset */ > #define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */ > #define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */ > +#define ISL1208_REG_SR_EVT (1<<3) /* event */ > #define ISL1208_REG_SR_ALM (1<<2) /* alarm */ > #define ISL1208_REG_SR_BAT (1<<1) /* battery */ > #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ > @@ -57,8 +60,29 @@ > #define ISL1208_REG_USR2 0x13 > #define ISL1208_USR_SECTION_LEN 2 > > +/* event section */ > +#define ISL1208_REG_SCT 0x14 > +#define ISL1208_REG_MNT 0x15 > +#define ISL1208_REG_HRT 0x16 > +#define ISL1208_REG_DTT 0x17 > +#define ISL1208_REG_MOT 0x18 > +#define ISL1208_REG_YRT 0x19 > +#define ISL1208_EVT_SECTION_LEN 6 > + > static struct i2c_driver isl1208_driver; > > +/* ISL1208 various variants */ > +enum { > + TYPE_ISL1208 = 0, > + TYPE_ISL1218, > + TYPE_ISL1219, > +}; > + > +struct isl1208 { > + struct rtc_device *rtc; > + struct device *hwmon; > +}; > + > /* block read */ > static int > isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], > @@ -80,8 +104,8 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], > }; > int ret; > > - BUG_ON(reg > ISL1208_REG_USR2); > - BUG_ON(reg + len > ISL1208_REG_USR2 + 1); > + WARN_ON(reg > ISL1208_REG_YRT); > + WARN_ON(reg + len > ISL1208_REG_YRT + 1); > > ret = i2c_transfer(client->adapter, msgs, 2); > if (ret > 0) > @@ -104,8 +128,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], > }; > int ret; > > - BUG_ON(reg > ISL1208_REG_USR2); > - BUG_ON(reg + len > ISL1208_REG_USR2 + 1); > + WARN_ON(reg > ISL1208_REG_YRT); > + WARN_ON(reg + len > ISL1208_REG_YRT + 1); > > i2c_buf[0] = reg; > memcpy(&i2c_buf[1], &buf[0], len); > @@ -493,12 +517,128 @@ isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) > return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm); > } > > +static ssize_t isl1208_hwmon_show_tamper(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct i2c_client *client = dev_get_drvdata(dev); > + int sr; > + > + sr = isl1208_i2c_get_sr(client); > + if (sr < 0) { > + dev_err(dev, "%s: reading SR failed\n", __func__); > + return sr; > + } > + > + if (sr & ISL1208_REG_SR_EVT) > + return sprintf(buf, "1\n"); > + > + return sprintf(buf, "0\n"); > +}; > + > +static ssize_t isl1208_hwmon_clear_caseopen(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + struct i2c_client *client = dev_get_drvdata(dev); > + unsigned long val; > + int sr; > + > + if (kstrtoul(buf, 10, &val) || val != 0) > + return -EINVAL; > + > + sr = isl1208_i2c_get_sr(client); > + if (sr < 0) { > + dev_err(dev, "%s: reading SR failed\n", __func__); > + return sr; > + } > + > + sr &= ~ISL1208_REG_SR_EVT; > + > + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); > + if (sr < 0) > + dev_err(dev, "%s: writing SR failed\n", > + __func__); > + > + return count; > +}; > + > +static ssize_t isl1208_hwmon_show_tamper_timestamp(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct i2c_client *client = dev_get_drvdata(dev); > + u8 regs[ISL1208_EVT_SECTION_LEN] = { 0, }; > + struct timespec64 tv64; > + struct rtc_time tm; > + int sr; > + > + sr = isl1208_i2c_get_sr(client); > + if (sr < 0) { > + dev_err(dev, "%s: reading SR failed\n", __func__); > + return sr; > + } > + > + if (!(sr & ISL1208_REG_SR_EVT)) > + return 0; > + > + sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCT, regs, > + ISL1208_EVT_SECTION_LEN); > + if (sr < 0) { > + dev_err(dev, "%s: reading event section failed\n", > + __func__); > + return 0; > + } > + > + /* MSB of each alarm register is an enable bit */ > + tm.tm_sec = bcd2bin(regs[ISL1208_REG_SCT - ISL1208_REG_SCT] & 0x7f); > + tm.tm_min = bcd2bin(regs[ISL1208_REG_MNT - ISL1208_REG_SCT] & 0x7f); > + tm.tm_hour = bcd2bin(regs[ISL1208_REG_HRT - ISL1208_REG_SCT] & 0x3f); > + tm.tm_mday = bcd2bin(regs[ISL1208_REG_DTT - ISL1208_REG_SCT] & 0x3f); > + tm.tm_mon = > + bcd2bin(regs[ISL1208_REG_MOT - ISL1208_REG_SCT] & 0x1f) - 1; > + tm.tm_year = bcd2bin(regs[ISL1208_REG_YRT - ISL1208_REG_SCT]) + 100; > + > + tv64.tv_sec = rtc_tm_to_time64(&tm); > + > + return sprintf(buf, > + "%d-%02d-%02d %02d:%02d:%02d UTC (%lld)\n", > + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, > + tm.tm_hour, tm.tm_min, tm.tm_sec, > + (long long) tv64.tv_sec); > +}; > + > +static SENSOR_DEVICE_ATTR(intrusion0_alarm, 0644, isl1208_hwmon_show_tamper, > + isl1208_hwmon_clear_caseopen, 0); > + > +static SENSOR_DEVICE_ATTR(intrusion0_timestamp, 0444, > + isl1208_hwmon_show_tamper_timestamp, NULL, 0); > + > +static struct attribute *isl1208_hwmon_attrs[] = { > + &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, > + &sensor_dev_attr_intrusion0_timestamp.dev_attr.attr, > + NULL, > +}; > +ATTRIBUTE_GROUPS(isl1208_hwmon); > + > +static void isl1208_hwmon_register(struct i2c_client *client) > +{ > + struct isl1208 *isl1208 = i2c_get_clientdata(client); > + > + isl1208->hwmon = devm_hwmon_device_register_with_groups(&client->dev, > + client->name, > + client, isl1208_hwmon_groups); > + if (IS_ERR(isl1208->hwmon)) { > + dev_warn(&client->dev, > + "unable to register hwmon device %ld\n", > + PTR_ERR(isl1208->hwmon)); > + } > +} > + > static irqreturn_t > isl1208_rtc_interrupt(int irq, void *data) > { > unsigned long timeout = jiffies + msecs_to_jiffies(1000); > struct i2c_client *client = data; > - struct rtc_device *rtc = i2c_get_clientdata(client); > + struct isl1208 *isl1208 = i2c_get_clientdata(client); > int handled = 0, sr, err; > > /* > @@ -521,7 +661,7 @@ isl1208_rtc_interrupt(int irq, void *data) > if (sr & ISL1208_REG_SR_ALM) { > dev_dbg(&client->dev, "alarm!\n"); > > - rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); > + rtc_update_irq(isl1208->rtc, 1, RTC_IRQF | RTC_AF); > > /* Clear the alarm */ > sr &= ~ISL1208_REG_SR_ALM; > @@ -538,6 +678,13 @@ isl1208_rtc_interrupt(int irq, void *data) > return err; > } > > + if (isl1208->hwmon && (sr & ISL1208_REG_SR_EVT)) { > + sysfs_notify(&isl1208->hwmon->kobj, NULL, > + sensor_dev_attr_intrusion0_alarm.dev_attr.attr.name); > + dev_warn(&client->dev, "event detected"); > + handled = 1; > + } > + > return handled ? IRQ_HANDLED : IRQ_NONE; > } > > @@ -627,7 +774,7 @@ static int > isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) > { > int rc = 0; > - struct rtc_device *rtc; > + struct isl1208 *isl1208; > > if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) > return -ENODEV; > @@ -635,13 +782,19 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) > if (isl1208_i2c_validate_client(client) < 0) > return -ENODEV; > > - rtc = devm_rtc_device_register(&client->dev, isl1208_driver.driver.name, > + isl1208 = devm_kzalloc(&client->dev, sizeof(struct isl1208), > + GFP_KERNEL); > + if (!isl1208) > + return -ENOMEM; > + > + isl1208->rtc = devm_rtc_device_register(&client->dev, > + isl1208_driver.driver.name, > &isl1208_rtc_ops, > THIS_MODULE); > - if (IS_ERR(rtc)) > - return PTR_ERR(rtc); > + if (IS_ERR(isl1208->rtc)) > + return PTR_ERR(isl1208->rtc); > > - i2c_set_clientdata(client, rtc); > + i2c_set_clientdata(client, isl1208); > > rc = isl1208_i2c_get_sr(client); > if (rc < 0) { > @@ -657,6 +810,15 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) > if (rc) > return rc; > > + if (id->driver_data == TYPE_ISL1219) { > + rc = i2c_smbus_write_byte_data(client, ISL1208_REG_09, 0x10); > + if (rc < 0) { > + dev_err(&client->dev, "could not enable tamper detection\n"); > + return rc; > + } > + isl1208_hwmon_register(client); > + } > + > if (client->irq > 0) { > rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, > isl1208_rtc_interrupt, > @@ -686,8 +848,9 @@ isl1208_remove(struct i2c_client *client) > } > > static const struct i2c_device_id isl1208_id[] = { > - { "isl1208", 0 }, > - { "isl1218", 0 }, > + { "isl1208", TYPE_ISL1208 }, > + { "isl1218", TYPE_ISL1218 }, > + { "isl1219", TYPE_ISL1219 }, > { } > }; > MODULE_DEVICE_TABLE(i2c, isl1208_id); > @@ -695,6 +858,7 @@ MODULE_DEVICE_TABLE(i2c, isl1208_id); > static const struct of_device_id isl1208_of_match[] = { > { .compatible = "isil,isl1208" }, > { .compatible = "isil,isl1218" }, > + { .compatible = "isil,isl1219" }, > { } > }; > MODULE_DEVICE_TABLE(of, isl1208_of_match); > -- > 2.11.0 >