From patchwork Fri Dec 23 22:12:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Koch X-Patchwork-Id: 9487703 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 5379D601C0 for ; Fri, 23 Dec 2016 22:13:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 44F5D204C2 for ; Fri, 23 Dec 2016 22:13:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3485020564; Fri, 23 Dec 2016 22:13:06 +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.0 required=2.0 tests=BAYES_00,DKIM_ADSP_ALL, DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID 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 AE96920748 for ; Fri, 23 Dec 2016 22:13:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758653AbcLWWND (ORCPT ); Fri, 23 Dec 2016 17:13:03 -0500 Received: from argos.tuxed.org ([176.9.87.227]:51074 "EHLO argos.tuxed.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753734AbcLWWNB (ORCPT ); Fri, 23 Dec 2016 17:13:01 -0500 Received: from thor.home.lan (unknown [IPv6:2a02:8071:3183:6700:8080:df34:b3ba:2cd1]) by argos.tuxed.org (Postfix) with ESMTPSA id 42D756E391; Fri, 23 Dec 2016 23:12:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=alexanderkoch.net; s=default; t=1482531159; bh=bsxaMMDH8dWQHMxyy0zmFJiJc2WZynkk9j4ZEWsg9zo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=p6RA3STmQBd4/cmHK3e3mgt5gOtf6V6j3VVNzJOM8IW6Pu9hmY2NbYE1eAWXFLnSB 0Pg1tiSGxsy52AWbAfYOHxk7zsGUEsv7RaOa5OJUHl6t2nfd4K00KbO0KXPRoHDX96 hDRuknj0CLyJubHkUpYvCzQNchlh8SB9SbpQskbA= From: Alexander Koch To: linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org, devicetree@vger.kernel.org Cc: Rob Herring , Mark Rutland , Jean Delvare , Guenter Roeck , Jiri Kosina , Alexander Koch Subject: [RFC PATCH v2 4/4] hwmon: adc128d818: Support operation modes 1-3 Date: Fri, 23 Dec 2016 23:12:05 +0100 Message-Id: <20161223221205.8825-5-mail@alexanderkoch.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20161223221205.8825-1-mail@alexanderkoch.net> References: <20161223221205.8825-1-mail@alexanderkoch.net> X-Virus-Scanned: clamav-milter 0.99.2 at argos X-Virus-Status: Clean 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 Add support for operation modes 1-3 of the ADC128D818 (see datasheet sec. 8.4.1). These differ in the number and type of the available input signals, requiring the driver to selectively hide sysfs nodes according to the operation mode configured via devicetree. Signed-off-by: Alexander Koch --- drivers/hwmon/adc128d818.c | 120 ++++++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 40 deletions(-) diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index cbb3bc5e5229..46c9fc9f1be2 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -59,6 +59,9 @@ static const unsigned short normal_i2c[] = { #define ADC128_REG_MAN_ID 0x3e #define ADC128_REG_DEV_ID 0x3f +/* Voltage inputs visible per operation mode */ +static const u8 num_inputs[] = { 7, 8, 4, 6 }; + struct adc128_data { struct i2c_client *client; struct regulator *regulator; @@ -68,7 +71,7 @@ struct adc128_data { bool valid; /* true if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u16 in[3][7]; /* Register value, normalized to 12 bit + u16 in[3][8]; /* Register value, normalized to 12 bit * 0: input voltage * 1: min limit * 2: max limit @@ -89,7 +92,7 @@ static struct adc128_data *adc128_update_device(struct device *dev) mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - for (i = 0; i < 7; i++) { + for (i = 0; i < num_inputs[data->mode]; i++) { rv = i2c_smbus_read_word_swapped(client, ADC128_REG_IN(i)); if (rv < 0) @@ -109,20 +112,25 @@ static struct adc128_data *adc128_update_device(struct device *dev) data->in[2][i] = rv << 4; } - rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP); - if (rv < 0) - goto abort; - data->temp[0] = rv >> 7; + if (data->mode != 1) { + rv = i2c_smbus_read_word_swapped(client, + ADC128_REG_TEMP); + if (rv < 0) + goto abort; + data->temp[0] = rv >> 7; - rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX); - if (rv < 0) - goto abort; - data->temp[1] = rv << 1; + rv = i2c_smbus_read_byte_data(client, + ADC128_REG_TEMP_MAX); + if (rv < 0) + goto abort; + data->temp[1] = rv << 1; - rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST); - if (rv < 0) - goto abort; - data->temp[2] = rv << 1; + rv = i2c_smbus_read_byte_data(client, + ADC128_REG_TEMP_HYST); + if (rv < 0) + goto abort; + data->temp[2] = rv << 1; + } rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM); if (rv < 0) @@ -242,6 +250,25 @@ static ssize_t adc128_show_alarm(struct device *dev, return sprintf(buf, "%u\n", !!(alarms & mask)); } +static umode_t adc128_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct adc128_data *data = dev_get_drvdata(dev); + + if (index < 8 * 4) { + /* Voltage, visible according to num_inputs[] */ + if (index >= num_inputs[data->mode] * 4) + return 0; + } else { + /* Temperature, visible if not in mode 1 */ + if (data->mode == 1) + return 0; + } + + return attr->mode; +} + static SENSOR_DEVICE_ATTR_2(in0_input, 0444, adc128_show_in, NULL, 0, 0); static SENSOR_DEVICE_ATTR_2(in0_min, 0644, adc128_show_in, adc128_set_in, 0, 1); static SENSOR_DEVICE_ATTR_2(in0_max, 0644, adc128_show_in, adc128_set_in, 0, 2); @@ -270,6 +297,10 @@ static SENSOR_DEVICE_ATTR_2(in6_input, 0444, adc128_show_in, NULL, 6, 0); static SENSOR_DEVICE_ATTR_2(in6_min, 0644, adc128_show_in, adc128_set_in, 6, 1); static SENSOR_DEVICE_ATTR_2(in6_max, 0644, adc128_show_in, adc128_set_in, 6, 2); +static SENSOR_DEVICE_ATTR_2(in7_input, 0444, adc128_show_in, NULL, 7, 0); +static SENSOR_DEVICE_ATTR_2(in7_min, 0644, adc128_show_in, adc128_set_in, 7, 1); +static SENSOR_DEVICE_ATTR_2(in7_max, 0644, adc128_show_in, adc128_set_in, 7, 2); + static SENSOR_DEVICE_ATTR(temp1_input, 0444, adc128_show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max, 0644, adc128_show_temp, adc128_set_temp, 1); @@ -283,44 +314,54 @@ static SENSOR_DEVICE_ATTR(in3_alarm, 0444, adc128_show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(in4_alarm, 0444, adc128_show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(in5_alarm, 0444, adc128_show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(in6_alarm, 0444, adc128_show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_alarm, 0444, adc128_show_alarm, NULL, 7); static SENSOR_DEVICE_ATTR(temp1_max_alarm, 0444, adc128_show_alarm, NULL, 7); static struct attribute *adc128_attrs[] = { - &sensor_dev_attr_in0_min.dev_attr.attr, - &sensor_dev_attr_in1_min.dev_attr.attr, - &sensor_dev_attr_in2_min.dev_attr.attr, - &sensor_dev_attr_in3_min.dev_attr.attr, - &sensor_dev_attr_in4_min.dev_attr.attr, - &sensor_dev_attr_in5_min.dev_attr.attr, - &sensor_dev_attr_in6_min.dev_attr.attr, - &sensor_dev_attr_in0_max.dev_attr.attr, - &sensor_dev_attr_in1_max.dev_attr.attr, - &sensor_dev_attr_in2_max.dev_attr.attr, - &sensor_dev_attr_in3_max.dev_attr.attr, - &sensor_dev_attr_in4_max.dev_attr.attr, - &sensor_dev_attr_in5_max.dev_attr.attr, - &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, - &sensor_dev_attr_in0_alarm.dev_attr.attr, - &sensor_dev_attr_in1_alarm.dev_attr.attr, - &sensor_dev_attr_in2_alarm.dev_attr.attr, - &sensor_dev_attr_in3_alarm.dev_attr.attr, - &sensor_dev_attr_in4_alarm.dev_attr.attr, - &sensor_dev_attr_in5_alarm.dev_attr.attr, - &sensor_dev_attr_in6_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, NULL }; -ATTRIBUTE_GROUPS(adc128); + +static struct attribute_group adc128_group = { + .attrs = adc128_attrs, + .is_visible = adc128_is_visible, +}; +__ATTRIBUTE_GROUPS(adc128); static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info) { @@ -425,9 +466,8 @@ static int adc128_probe(struct i2c_client *client, /* Operation mode is optional and defaults to mode 0 */ if (of_property_read_u8(dev->of_node, "mode", &data->mode) == 0) { - /* Currently only mode 0 supported */ - if (data->mode != 0) { - dev_err(dev, "unsupported operation mode %d", + if (data->mode > 3) { + dev_err(dev, "invalid operation mode %d", data->mode); err = -EINVAL; goto error;