hwmon: (adt7475) Add attenuator bypass support
authorLogan Shaw <logan.shaw@alliedtelesis.co.nz>
Thu, 27 Feb 2020 08:46:41 +0000 (21:46 +1300)
committerGuenter Roeck <linux@roeck-us.net>
Mon, 9 Mar 2020 03:35:47 +0000 (20:35 -0700)
Added support for reading DTS properties to set attenuators on
device probe for the ADT7473, ADT7475, ADT7476, and ADT7490.

Signed-off-by: Logan Shaw <logan.shaw@alliedtelesis.co.nz>
Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
[groeck: Continuation line formatting; dev_err -> dev_warn]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/adt7475.c

index 01c2eeb..79e50e6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/jiffies.h>
+#include <linux/of.h>
 #include <linux/util_macros.h>
 
 /* Indexes for the sysfs hooks */
@@ -193,6 +194,7 @@ struct adt7475_data {
        unsigned long measure_updated;
        bool valid;
 
+       u8 config2;
        u8 config4;
        u8 config5;
        u8 has_voltage;
@@ -1458,6 +1460,55 @@ static int adt7475_update_limits(struct i2c_client *client)
        return 0;
 }
 
+static int set_property_bit(const struct i2c_client *client, char *property,
+                           u8 *config, u8 bit_index)
+{
+       u32 prop_value = 0;
+       int ret = of_property_read_u32(client->dev.of_node, property,
+                                       &prop_value);
+
+       if (!ret) {
+               if (prop_value)
+                       *config |= (1 << bit_index);
+               else
+                       *config &= ~(1 << bit_index);
+       }
+
+       return ret;
+}
+
+static int load_attenuators(const struct i2c_client *client, int chip,
+                           struct adt7475_data *data)
+{
+       int ret;
+
+       if (chip == adt7476 || chip == adt7490) {
+               set_property_bit(client, "adi,bypass-attenuator-in0",
+                                &data->config4, 4);
+               set_property_bit(client, "adi,bypass-attenuator-in1",
+                                &data->config4, 5);
+               set_property_bit(client, "adi,bypass-attenuator-in3",
+                                &data->config4, 6);
+               set_property_bit(client, "adi,bypass-attenuator-in4",
+                                &data->config4, 7);
+
+               ret = i2c_smbus_write_byte_data(client, REG_CONFIG4,
+                                               data->config4);
+               if (ret < 0)
+                       return ret;
+       } else if (chip == adt7473 || chip == adt7475) {
+               set_property_bit(client, "adi,bypass-attenuator-in1",
+                                &data->config2, 5);
+
+               ret = i2c_smbus_write_byte_data(client, REG_CONFIG2,
+                                               data->config2);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int adt7475_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -1472,7 +1523,7 @@ static int adt7475_probe(struct i2c_client *client,
        struct adt7475_data *data;
        struct device *hwmon_dev;
        int i, ret = 0, revision, group_num = 0;
-       u8 config2, config3;
+       u8 config3;
 
        data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
        if (data == NULL)
@@ -1546,8 +1597,12 @@ static int adt7475_probe(struct i2c_client *client,
        }
 
        /* Voltage attenuators can be bypassed, globally or individually */
-       config2 = adt7475_read(REG_CONFIG2);
-       if (config2 & CONFIG2_ATTN) {
+       data->config2 = adt7475_read(REG_CONFIG2);
+       ret = load_attenuators(client, chip, data);
+       if (ret)
+               dev_warn(&client->dev, "Error configuring attenuator bypass\n");
+
+       if (data->config2 & CONFIG2_ATTN) {
                data->bypass_attn = (0x3 << 3) | 0x3;
        } else {
                data->bypass_attn = ((data->config4 & CONFIG4_ATTN_IN10) >> 4) |