From patchwork Tue May 31 16:27:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrew Davis X-Patchwork-Id: 9145147 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B109560757 for ; Tue, 31 May 2016 16:28:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A2D571FF45 for ; Tue, 31 May 2016 16:28:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 973B527BF0; Tue, 31 May 2016 16:28:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D47741FF45 for ; Tue, 31 May 2016 16:28:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752885AbcEaQ2I (ORCPT ); Tue, 31 May 2016 12:28:08 -0400 Received: from arroyo.ext.ti.com ([198.47.19.12]:40779 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751288AbcEaQ2G (ORCPT ); Tue, 31 May 2016 12:28:06 -0400 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id u4VGRLC6021996; Tue, 31 May 2016 11:27:21 -0500 Received: from DLEE71.ent.ti.com (dlee71.ent.ti.com [157.170.170.114]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id u4VGRLO1028156; Tue, 31 May 2016 11:27:21 -0500 Received: from dlep33.itg.ti.com (157.170.170.75) by DLEE71.ent.ti.com (157.170.170.114) with Microsoft SMTP Server id 14.3.294.0; Tue, 31 May 2016 11:27:21 -0500 Received: from legion.dal.design.ti.com (legion.dal.design.ti.com [128.247.22.53]) by dlep33.itg.ti.com (8.14.3/8.13.8) with ESMTP id u4VGRK5q006101; Tue, 31 May 2016 11:27:20 -0500 Received: from localhost (uda0226330.am.dhcp.ti.com [128.247.83.127]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id u4VGRK315394; Tue, 31 May 2016 11:27:20 -0500 (CDT) From: "Andrew F. Davis" To: Guenter Roeck , Jean Delvare , Jonathan Corbet CC: , , , "Andrew F . Davis" Subject: [PATCH] hwmon: (tmp401) Add support for TI TMP461 Date: Tue, 31 May 2016 11:27:20 -0500 Message-ID: <20160531162720.460-1-afd@ti.com> X-Mailer: git-send-email 2.8.3 MIME-Version: 1.0 Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Andrew F. Davis --- Documentation/hwmon/tmp401 | 18 +++++++++-- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/tmp401.c | 81 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401 index 711f75e..eaa2d3b 100644 --- a/Documentation/hwmon/tmp401 +++ b/Documentation/hwmon/tmp401 @@ -22,6 +22,9 @@ Supported chips: Prefix: 'tmp435' Addresses scanned: I2C 0x48 - 0x4f Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html + * Texas Instruments TMP461 + Prefix: 'tmp461' + Datasheet: http://www.ti.com/product/tmp461 Authors: Hans de Goede @@ -31,8 +34,8 @@ Description ----------- This driver implements support for Texas Instruments TMP401, TMP411, -TMP431, TMP432 and TMP435 chips. These chips implement one or two remote -and one local temperature sensors. Temperature is measured in degrees +TMP431, TMP432, TMP435, and TMP461 chips. These chips implement one or two +remote and one local temperature sensors. Temperature is measured in degrees Celsius. Resolution of the remote sensor is 0.0625 degree. Local sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not supported by the driver so far, so using the default resolution of 0.5 @@ -55,3 +58,14 @@ some additional features. TMP432 is compatible with TMP401 and TMP431. It supports two external temperature sensors. + +TMP461 is compatible with TMP401. It supports offset and n-factor correction +that is applied to the remote sensor. + +* Sensor offset values are temperature values + + Exported via sysfs attribute tempX_offset + +* n-factor correction, values are in raw form as described in the datasheet + + Exported via sysfs attribute tempX_nfactor diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ff94007..c571dcf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1561,7 +1561,7 @@ config SENSORS_TMP401 depends on I2C help If you say yes here you get support for Texas Instruments TMP401, - TMP411, TMP431, TMP432 and TMP435 temperature sensor chips. + TMP411, TMP431, TMP432, TMP435, and TMP461 temperature sensor chips. This driver can also be built as a module. If so, the module will be called tmp401. diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index ccf4cff..280065b 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -47,7 +47,8 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; +enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 }; + /* * The TMP401 registers, note some registers have different addresses for @@ -62,31 +63,37 @@ enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; #define TMP401_MANUFACTURER_ID_REG 0xFE #define TMP401_DEVICE_ID_REG 0xFF -static const u8 TMP401_TEMP_MSB_READ[6][2] = { +static const u8 TMP401_TEMP_MSB_READ[8][2] = { { 0x00, 0x01 }, /* temp */ { 0x06, 0x08 }, /* low limit */ { 0x05, 0x07 }, /* high limit */ { 0x20, 0x19 }, /* therm (crit) limit */ { 0x30, 0x34 }, /* lowest */ { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ + { 0, 0x23 }, /* nfactor */ }; -static const u8 TMP401_TEMP_MSB_WRITE[6][2] = { +static const u8 TMP401_TEMP_MSB_WRITE[8][2] = { { 0, 0 }, /* temp (unused) */ { 0x0C, 0x0E }, /* low limit */ { 0x0B, 0x0D }, /* high limit */ { 0x20, 0x19 }, /* therm (crit) limit */ { 0x30, 0x34 }, /* lowest */ { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ + { 0, 0x23 }, /* nfactor */ }; -static const u8 TMP401_TEMP_LSB[6][2] = { +static const u8 TMP401_TEMP_LSB[8][2] = { { 0x15, 0x10 }, /* temp */ { 0x17, 0x14 }, /* low limit */ { 0x16, 0x13 }, /* high limit */ { 0, 0 }, /* therm (crit) limit (unused) */ { 0x31, 0x35 }, /* lowest */ { 0x33, 0x37 }, /* highest */ + { 0, 0x12 }, /* offset */ + { 0, 0 }, /* nfactor (unused) */ }; static const u8 TMP432_TEMP_MSB_READ[4][3] = { @@ -149,6 +156,7 @@ static const struct i2c_device_id tmp401_id[] = { { "tmp431", tmp431 }, { "tmp432", tmp432 }, { "tmp435", tmp435 }, + { "tmp461", tmp461 }, { } }; MODULE_DEVICE_TABLE(i2c, tmp401_id); @@ -170,7 +178,7 @@ struct tmp401_data { /* register values */ u8 status[4]; u8 config; - u16 temp[6][3]; + u16 temp[8][3]; u8 temp_crit_hyst; }; @@ -445,6 +453,44 @@ static ssize_t reset_temp_history(struct device *dev, return count; } +static ssize_t show_nfactor(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int index = to_sensor_dev_attr_2(devattr)->index; + struct tmp401_data *data = tmp401_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->temp[nr][index]); +} + +static ssize_t store_nfactor(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr_2(devattr)->nr; + int index = to_sensor_dev_attr_2(devattr)->index; + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + long val; + u8 regaddr; + + if (kstrtol(buf, 10, &val)) + return -EINVAL; + val = clamp_val(val, -128, 127); + + regaddr = TMP401_TEMP_MSB_WRITE[nr][index]; + + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(client, regaddr, val); + data->temp[nr][index] = val; + mutex_unlock(&data->update_lock); + + return count; +} + static ssize_t show_update_interval(struct device *dev, struct device_attribute *attr, char *buf) { @@ -613,6 +659,26 @@ static const struct attribute_group tmp432_group = { }; /* + * Additional features of the TMP461 chip. + * The TMP461 η-factor correction and temperature offset + * for the remote channel. + */ +static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp, + store_temp, 6, 1); +static SENSOR_DEVICE_ATTR_2(temp2_nfactor, S_IWUSR | S_IRUGO, show_nfactor, + store_nfactor, 7, 1); + +static struct attribute *tmp461_attributes[] = { + &sensor_dev_attr_temp2_offset.dev_attr.attr, + &sensor_dev_attr_temp2_nfactor.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp461_group = { + .attrs = tmp461_attributes, +}; + +/* * Begin non sysfs callback code (aka Real code) */ @@ -714,7 +780,7 @@ static int tmp401_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const char * const names[] = { - "TMP401", "TMP411", "TMP431", "TMP432", "TMP435" + "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" }; struct device *dev = &client->dev; struct device *hwmon_dev; @@ -745,6 +811,9 @@ static int tmp401_probe(struct i2c_client *client, if (data->kind == tmp432) data->groups[groups++] = &tmp432_group; + if (data->kind == tmp461) + data->groups[groups++] = &tmp461_group; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, data, data->groups); if (IS_ERR(hwmon_dev))