Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * sbtsi_temp.c - hwmon driver for a SBI Temperature Sensor Interface (SB-TSI)
0004  *                compliant AMD SoC temperature device.
0005  *
0006  * Copyright (c) 2020, Google Inc.
0007  * Copyright (c) 2020, Kun Yi <kunyi@google.com>
0008  */
0009 
0010 #include <linux/err.h>
0011 #include <linux/i2c.h>
0012 #include <linux/init.h>
0013 #include <linux/hwmon.h>
0014 #include <linux/module.h>
0015 #include <linux/mutex.h>
0016 #include <linux/of_device.h>
0017 #include <linux/of.h>
0018 
0019 /*
0020  * SB-TSI registers only support SMBus byte data access. "_INT" registers are
0021  * the integer part of a temperature value or limit, and "_DEC" registers are
0022  * corresponding decimal parts.
0023  */
0024 #define SBTSI_REG_TEMP_INT      0x01 /* RO */
0025 #define SBTSI_REG_STATUS        0x02 /* RO */
0026 #define SBTSI_REG_CONFIG        0x03 /* RO */
0027 #define SBTSI_REG_TEMP_HIGH_INT     0x07 /* RW */
0028 #define SBTSI_REG_TEMP_LOW_INT      0x08 /* RW */
0029 #define SBTSI_REG_TEMP_DEC      0x10 /* RW */
0030 #define SBTSI_REG_TEMP_HIGH_DEC     0x13 /* RW */
0031 #define SBTSI_REG_TEMP_LOW_DEC      0x14 /* RW */
0032 
0033 #define SBTSI_CONFIG_READ_ORDER_SHIFT   5
0034 
0035 #define SBTSI_TEMP_MIN  0
0036 #define SBTSI_TEMP_MAX  255875
0037 
0038 /* Each client has this additional data */
0039 struct sbtsi_data {
0040     struct i2c_client *client;
0041     struct mutex lock;
0042 };
0043 
0044 /*
0045  * From SB-TSI spec: CPU temperature readings and limit registers encode the
0046  * temperature in increments of 0.125 from 0 to 255.875. The "high byte"
0047  * register encodes the base-2 of the integer portion, and the upper 3 bits of
0048  * the "low byte" encode in base-2 the decimal portion.
0049  *
0050  * e.g. INT=0x19, DEC=0x20 represents 25.125 degrees Celsius
0051  *
0052  * Therefore temperature in millidegree Celsius =
0053  *   (INT + DEC / 256) * 1000 = (INT * 8 + DEC / 32) * 125
0054  */
0055 static inline int sbtsi_reg_to_mc(s32 integer, s32 decimal)
0056 {
0057     return ((integer << 3) + (decimal >> 5)) * 125;
0058 }
0059 
0060 /*
0061  * Inversely, given temperature in millidegree Celsius
0062  *   INT = (TEMP / 125) / 8
0063  *   DEC = ((TEMP / 125) % 8) * 32
0064  * Caller have to make sure temp doesn't exceed 255875, the max valid value.
0065  */
0066 static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal)
0067 {
0068     temp /= 125;
0069     *integer = temp >> 3;
0070     *decimal = (temp & 0x7) << 5;
0071 }
0072 
0073 static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type,
0074               u32 attr, int channel, long *val)
0075 {
0076     struct sbtsi_data *data = dev_get_drvdata(dev);
0077     s32 temp_int, temp_dec;
0078     int err;
0079 
0080     switch (attr) {
0081     case hwmon_temp_input:
0082         /*
0083          * ReadOrder bit specifies the reading order of integer and
0084          * decimal part of CPU temp for atomic reads. If bit == 0,
0085          * reading integer part triggers latching of the decimal part,
0086          * so integer part should be read first. If bit == 1, read
0087          * order should be reversed.
0088          */
0089         err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
0090         if (err < 0)
0091             return err;
0092 
0093         mutex_lock(&data->lock);
0094         if (err & BIT(SBTSI_CONFIG_READ_ORDER_SHIFT)) {
0095             temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
0096             temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
0097         } else {
0098             temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
0099             temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
0100         }
0101         mutex_unlock(&data->lock);
0102         break;
0103     case hwmon_temp_max:
0104         mutex_lock(&data->lock);
0105         temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_INT);
0106         temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_DEC);
0107         mutex_unlock(&data->lock);
0108         break;
0109     case hwmon_temp_min:
0110         mutex_lock(&data->lock);
0111         temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_INT);
0112         temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_DEC);
0113         mutex_unlock(&data->lock);
0114         break;
0115     default:
0116         return -EINVAL;
0117     }
0118 
0119 
0120     if (temp_int < 0)
0121         return temp_int;
0122     if (temp_dec < 0)
0123         return temp_dec;
0124 
0125     *val = sbtsi_reg_to_mc(temp_int, temp_dec);
0126 
0127     return 0;
0128 }
0129 
0130 static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type,
0131                u32 attr, int channel, long val)
0132 {
0133     struct sbtsi_data *data = dev_get_drvdata(dev);
0134     int reg_int, reg_dec, err;
0135     u8 temp_int, temp_dec;
0136 
0137     switch (attr) {
0138     case hwmon_temp_max:
0139         reg_int = SBTSI_REG_TEMP_HIGH_INT;
0140         reg_dec = SBTSI_REG_TEMP_HIGH_DEC;
0141         break;
0142     case hwmon_temp_min:
0143         reg_int = SBTSI_REG_TEMP_LOW_INT;
0144         reg_dec = SBTSI_REG_TEMP_LOW_DEC;
0145         break;
0146     default:
0147         return -EINVAL;
0148     }
0149 
0150     val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX);
0151     sbtsi_mc_to_reg(val, &temp_int, &temp_dec);
0152 
0153     mutex_lock(&data->lock);
0154     err = i2c_smbus_write_byte_data(data->client, reg_int, temp_int);
0155     if (err)
0156         goto exit;
0157 
0158     err = i2c_smbus_write_byte_data(data->client, reg_dec, temp_dec);
0159 exit:
0160     mutex_unlock(&data->lock);
0161     return err;
0162 }
0163 
0164 static umode_t sbtsi_is_visible(const void *data,
0165                 enum hwmon_sensor_types type,
0166                 u32 attr, int channel)
0167 {
0168     switch (type) {
0169     case hwmon_temp:
0170         switch (attr) {
0171         case hwmon_temp_input:
0172             return 0444;
0173         case hwmon_temp_min:
0174             return 0644;
0175         case hwmon_temp_max:
0176             return 0644;
0177         }
0178         break;
0179     default:
0180         break;
0181     }
0182     return 0;
0183 }
0184 
0185 static const struct hwmon_channel_info *sbtsi_info[] = {
0186     HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
0187     HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX),
0188     NULL
0189 };
0190 
0191 static const struct hwmon_ops sbtsi_hwmon_ops = {
0192     .is_visible = sbtsi_is_visible,
0193     .read = sbtsi_read,
0194     .write = sbtsi_write,
0195 };
0196 
0197 static const struct hwmon_chip_info sbtsi_chip_info = {
0198     .ops = &sbtsi_hwmon_ops,
0199     .info = sbtsi_info,
0200 };
0201 
0202 static int sbtsi_probe(struct i2c_client *client,
0203                const struct i2c_device_id *id)
0204 {
0205     struct device *dev = &client->dev;
0206     struct device *hwmon_dev;
0207     struct sbtsi_data *data;
0208 
0209     data = devm_kzalloc(dev, sizeof(struct sbtsi_data), GFP_KERNEL);
0210     if (!data)
0211         return -ENOMEM;
0212 
0213     data->client = client;
0214     mutex_init(&data->lock);
0215 
0216     hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &sbtsi_chip_info,
0217                              NULL);
0218 
0219     return PTR_ERR_OR_ZERO(hwmon_dev);
0220 }
0221 
0222 static const struct i2c_device_id sbtsi_id[] = {
0223     {"sbtsi", 0},
0224     {}
0225 };
0226 MODULE_DEVICE_TABLE(i2c, sbtsi_id);
0227 
0228 static const struct of_device_id __maybe_unused sbtsi_of_match[] = {
0229     {
0230         .compatible = "amd,sbtsi",
0231     },
0232     { },
0233 };
0234 MODULE_DEVICE_TABLE(of, sbtsi_of_match);
0235 
0236 static struct i2c_driver sbtsi_driver = {
0237     .class = I2C_CLASS_HWMON,
0238     .driver = {
0239         .name = "sbtsi",
0240         .of_match_table = of_match_ptr(sbtsi_of_match),
0241     },
0242     .probe = sbtsi_probe,
0243     .id_table = sbtsi_id,
0244 };
0245 
0246 module_i2c_driver(sbtsi_driver);
0247 
0248 MODULE_AUTHOR("Kun Yi <kunyi@google.com>");
0249 MODULE_DESCRIPTION("Hwmon driver for AMD SB-TSI emulated sensor");
0250 MODULE_LICENSE("GPL");