at master 6.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * sbtsi_temp.c - hwmon driver for a SBI Temperature Sensor Interface (SB-TSI) 4 * compliant AMD SoC temperature device. 5 * 6 * Copyright (c) 2020, Google Inc. 7 * Copyright (c) 2020, Kun Yi <kunyi@google.com> 8 */ 9 10#include <linux/err.h> 11#include <linux/i2c.h> 12#include <linux/init.h> 13#include <linux/hwmon.h> 14#include <linux/module.h> 15#include <linux/of.h> 16#include <linux/bitfield.h> 17 18/* 19 * SB-TSI registers only support SMBus byte data access. "_INT" registers are 20 * the integer part of a temperature value or limit, and "_DEC" registers are 21 * corresponding decimal parts. 22 */ 23#define SBTSI_REG_TEMP_INT 0x01 /* RO */ 24#define SBTSI_REG_STATUS 0x02 /* RO */ 25#define SBTSI_REG_CONFIG 0x03 /* RO */ 26#define SBTSI_REG_TEMP_HIGH_INT 0x07 /* RW */ 27#define SBTSI_REG_TEMP_LOW_INT 0x08 /* RW */ 28#define SBTSI_REG_TEMP_DEC 0x10 /* RW */ 29#define SBTSI_REG_TEMP_HIGH_DEC 0x13 /* RW */ 30#define SBTSI_REG_TEMP_LOW_DEC 0x14 /* RW */ 31 32/* 33 * Bit for reporting value with temperature measurement range. 34 * bit == 0: Use default temperature range (0C to 255.875C). 35 * bit == 1: Use extended temperature range (-49C to +206.875C). 36 */ 37#define SBTSI_CONFIG_EXT_RANGE_SHIFT 2 38/* 39 * ReadOrder bit specifies the reading order of integer and decimal part of 40 * CPU temperature for atomic reads. If bit == 0, reading integer part triggers 41 * latching of the decimal part, so integer part should be read first. 42 * If bit == 1, read order should be reversed. 43 */ 44#define SBTSI_CONFIG_READ_ORDER_SHIFT 5 45 46#define SBTSI_TEMP_EXT_RANGE_ADJ 49000 47 48#define SBTSI_TEMP_MIN 0 49#define SBTSI_TEMP_MAX 255875 50 51/* Each client has this additional data */ 52struct sbtsi_data { 53 struct i2c_client *client; 54 bool ext_range_mode; 55 bool read_order; 56}; 57 58/* 59 * From SB-TSI spec: CPU temperature readings and limit registers encode the 60 * temperature in increments of 0.125 from 0 to 255.875. The "high byte" 61 * register encodes the base-2 of the integer portion, and the upper 3 bits of 62 * the "low byte" encode in base-2 the decimal portion. 63 * 64 * e.g. INT=0x19, DEC=0x20 represents 25.125 degrees Celsius 65 * 66 * Therefore temperature in millidegree Celsius = 67 * (INT + DEC / 256) * 1000 = (INT * 8 + DEC / 32) * 125 68 */ 69static inline int sbtsi_reg_to_mc(s32 integer, s32 decimal) 70{ 71 return ((integer << 3) + (decimal >> 5)) * 125; 72} 73 74/* 75 * Inversely, given temperature in millidegree Celsius 76 * INT = (TEMP / 125) / 8 77 * DEC = ((TEMP / 125) % 8) * 32 78 * Caller have to make sure temp doesn't exceed 255875, the max valid value. 79 */ 80static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal) 81{ 82 temp /= 125; 83 *integer = temp >> 3; 84 *decimal = (temp & 0x7) << 5; 85} 86 87static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type, 88 u32 attr, int channel, long *val) 89{ 90 struct sbtsi_data *data = dev_get_drvdata(dev); 91 s32 temp_int, temp_dec; 92 93 switch (attr) { 94 case hwmon_temp_input: 95 if (data->read_order) { 96 temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC); 97 temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT); 98 } else { 99 temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT); 100 temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC); 101 } 102 break; 103 case hwmon_temp_max: 104 temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_INT); 105 temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_DEC); 106 break; 107 case hwmon_temp_min: 108 temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_INT); 109 temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_DEC); 110 break; 111 default: 112 return -EINVAL; 113 } 114 115 116 if (temp_int < 0) 117 return temp_int; 118 if (temp_dec < 0) 119 return temp_dec; 120 121 *val = sbtsi_reg_to_mc(temp_int, temp_dec); 122 if (data->ext_range_mode) 123 *val -= SBTSI_TEMP_EXT_RANGE_ADJ; 124 125 return 0; 126} 127 128static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type, 129 u32 attr, int channel, long val) 130{ 131 struct sbtsi_data *data = dev_get_drvdata(dev); 132 int reg_int, reg_dec, err; 133 u8 temp_int, temp_dec; 134 135 switch (attr) { 136 case hwmon_temp_max: 137 reg_int = SBTSI_REG_TEMP_HIGH_INT; 138 reg_dec = SBTSI_REG_TEMP_HIGH_DEC; 139 break; 140 case hwmon_temp_min: 141 reg_int = SBTSI_REG_TEMP_LOW_INT; 142 reg_dec = SBTSI_REG_TEMP_LOW_DEC; 143 break; 144 default: 145 return -EINVAL; 146 } 147 148 if (data->ext_range_mode) 149 val += SBTSI_TEMP_EXT_RANGE_ADJ; 150 val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX); 151 sbtsi_mc_to_reg(val, &temp_int, &temp_dec); 152 153 err = i2c_smbus_write_byte_data(data->client, reg_int, temp_int); 154 if (err) 155 return err; 156 157 return i2c_smbus_write_byte_data(data->client, reg_dec, temp_dec); 158} 159 160static umode_t sbtsi_is_visible(const void *data, 161 enum hwmon_sensor_types type, 162 u32 attr, int channel) 163{ 164 switch (type) { 165 case hwmon_temp: 166 switch (attr) { 167 case hwmon_temp_input: 168 return 0444; 169 case hwmon_temp_min: 170 return 0644; 171 case hwmon_temp_max: 172 return 0644; 173 } 174 break; 175 default: 176 break; 177 } 178 return 0; 179} 180 181static const struct hwmon_channel_info * const sbtsi_info[] = { 182 HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), 183 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX), 184 NULL 185}; 186 187static const struct hwmon_ops sbtsi_hwmon_ops = { 188 .is_visible = sbtsi_is_visible, 189 .read = sbtsi_read, 190 .write = sbtsi_write, 191}; 192 193static const struct hwmon_chip_info sbtsi_chip_info = { 194 .ops = &sbtsi_hwmon_ops, 195 .info = sbtsi_info, 196}; 197 198static int sbtsi_probe(struct i2c_client *client) 199{ 200 struct device *dev = &client->dev; 201 struct device *hwmon_dev; 202 struct sbtsi_data *data; 203 int err; 204 205 data = devm_kzalloc(dev, sizeof(struct sbtsi_data), GFP_KERNEL); 206 if (!data) 207 return -ENOMEM; 208 209 data->client = client; 210 211 err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG); 212 if (err < 0) 213 return err; 214 data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), err); 215 data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err); 216 217 hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, 218 &sbtsi_chip_info, NULL); 219 220 return PTR_ERR_OR_ZERO(hwmon_dev); 221} 222 223static const struct i2c_device_id sbtsi_id[] = { 224 {"sbtsi"}, 225 {} 226}; 227MODULE_DEVICE_TABLE(i2c, sbtsi_id); 228 229static const struct of_device_id __maybe_unused sbtsi_of_match[] = { 230 { 231 .compatible = "amd,sbtsi", 232 }, 233 { }, 234}; 235MODULE_DEVICE_TABLE(of, sbtsi_of_match); 236 237static struct i2c_driver sbtsi_driver = { 238 .driver = { 239 .name = "sbtsi", 240 .of_match_table = of_match_ptr(sbtsi_of_match), 241 }, 242 .probe = sbtsi_probe, 243 .id_table = sbtsi_id, 244}; 245 246module_i2c_driver(sbtsi_driver); 247 248MODULE_AUTHOR("Kun Yi <kunyi@google.com>"); 249MODULE_DESCRIPTION("Hwmon driver for AMD SB-TSI emulated sensor"); 250MODULE_LICENSE("GPL");