root/drivers/hwmon/tc74.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tc74_update_device
  2. temp_input_show
  3. tc74_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * An hwmon driver for the Microchip TC74
   4  *
   5  * Copyright 2015 Maciej Szmigiero <mail@maciej.szmigiero.name>
   6  *
   7  * Based on ad7414.c:
   8  *      Copyright 2006 Stefan Roese, DENX Software Engineering
   9  *      Copyright 2008 Sean MacLennan, PIKA Technologies
  10  *      Copyright 2008 Frank Edelhaeuser, Spansion Inc.
  11  */
  12 
  13 #include <linux/bitops.h>
  14 #include <linux/err.h>
  15 #include <linux/hwmon.h>
  16 #include <linux/hwmon-sysfs.h>
  17 #include <linux/i2c.h>
  18 #include <linux/jiffies.h>
  19 #include <linux/module.h>
  20 #include <linux/mutex.h>
  21 #include <linux/slab.h>
  22 #include <linux/sysfs.h>
  23 
  24 /* TC74 registers */
  25 #define TC74_REG_TEMP           0x00
  26 #define TC74_REG_CONFIG         0x01
  27 
  28 struct tc74_data {
  29         struct i2c_client       *client;
  30         struct mutex            lock;   /* atomic read data updates */
  31         bool                    valid;  /* validity of fields below */
  32         unsigned long           next_update;    /* In jiffies */
  33         s8                      temp_input;     /* Temp value in dC */
  34 };
  35 
  36 static int tc74_update_device(struct device *dev)
  37 {
  38         struct tc74_data *data = dev_get_drvdata(dev);
  39         struct i2c_client *client = data->client;
  40         int ret;
  41 
  42         ret = mutex_lock_interruptible(&data->lock);
  43         if (ret)
  44                 return ret;
  45 
  46         if (time_after(jiffies, data->next_update) || !data->valid) {
  47                 s32 value;
  48 
  49                 value = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
  50                 if (value < 0) {
  51                         dev_dbg(&client->dev, "TC74_REG_CONFIG read err %d\n",
  52                                 (int)value);
  53 
  54                         ret = value;
  55                         goto ret_unlock;
  56                 }
  57 
  58                 if (!(value & BIT(6))) {
  59                         /* not ready yet */
  60 
  61                         ret = -EAGAIN;
  62                         goto ret_unlock;
  63                 }
  64 
  65                 value = i2c_smbus_read_byte_data(client, TC74_REG_TEMP);
  66                 if (value < 0) {
  67                         dev_dbg(&client->dev, "TC74_REG_TEMP read err %d\n",
  68                                 (int)value);
  69 
  70                         ret = value;
  71                         goto ret_unlock;
  72                 }
  73 
  74                 data->temp_input = value;
  75                 data->next_update = jiffies + HZ / 4;
  76                 data->valid = true;
  77         }
  78 
  79 ret_unlock:
  80         mutex_unlock(&data->lock);
  81 
  82         return ret;
  83 }
  84 
  85 static ssize_t temp_input_show(struct device *dev,
  86                                struct device_attribute *attr, char *buf)
  87 {
  88         struct tc74_data *data = dev_get_drvdata(dev);
  89         int ret;
  90 
  91         ret = tc74_update_device(dev);
  92         if (ret)
  93                 return ret;
  94 
  95         return sprintf(buf, "%d\n", data->temp_input * 1000);
  96 }
  97 static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0);
  98 
  99 static struct attribute *tc74_attrs[] = {
 100         &sensor_dev_attr_temp1_input.dev_attr.attr,
 101         NULL
 102 };
 103 
 104 ATTRIBUTE_GROUPS(tc74);
 105 
 106 static int tc74_probe(struct i2c_client *client,
 107                       const struct i2c_device_id *dev_id)
 108 {
 109         struct device *dev = &client->dev;
 110         struct tc74_data *data;
 111         struct device *hwmon_dev;
 112         s32 conf;
 113 
 114         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 115                 return -EOPNOTSUPP;
 116 
 117         data = devm_kzalloc(dev, sizeof(struct tc74_data), GFP_KERNEL);
 118         if (!data)
 119                 return -ENOMEM;
 120 
 121         data->client = client;
 122         mutex_init(&data->lock);
 123 
 124         /* Make sure the chip is powered up. */
 125         conf = i2c_smbus_read_byte_data(client, TC74_REG_CONFIG);
 126         if (conf < 0) {
 127                 dev_err(dev, "unable to read config register\n");
 128 
 129                 return conf;
 130         }
 131 
 132         if (conf & 0x3f) {
 133                 dev_err(dev, "invalid config register value\n");
 134 
 135                 return -ENODEV;
 136         }
 137 
 138         if (conf & BIT(7)) {
 139                 s32 ret;
 140 
 141                 conf &= ~BIT(7);
 142 
 143                 ret = i2c_smbus_write_byte_data(client, TC74_REG_CONFIG, conf);
 144                 if (ret)
 145                         dev_warn(dev, "unable to disable STANDBY\n");
 146         }
 147 
 148         hwmon_dev = devm_hwmon_device_register_with_groups(dev,
 149                                                            client->name,
 150                                                            data, tc74_groups);
 151         return PTR_ERR_OR_ZERO(hwmon_dev);
 152 }
 153 
 154 static const struct i2c_device_id tc74_id[] = {
 155         { "tc74", 0 },
 156         {}
 157 };
 158 MODULE_DEVICE_TABLE(i2c, tc74_id);
 159 
 160 static struct i2c_driver tc74_driver = {
 161         .driver = {
 162                 .name   = "tc74",
 163         },
 164         .probe  = tc74_probe,
 165         .id_table = tc74_id,
 166 };
 167 
 168 module_i2c_driver(tc74_driver);
 169 
 170 MODULE_AUTHOR("Maciej Szmigiero <mail@maciej.szmigiero.name>");
 171 
 172 MODULE_DESCRIPTION("TC74 driver");
 173 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */