brintos

brintos / linux-shallow public Read only

0
0
Text · 10.4 KiB · 761c130 Raw
403 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring4 *5 * Copyright (C) 2006 Corentin LABBE <clabbe.montjoie@gmail.com>6 *7 * Based on LM83 Driver by Jean Delvare <jdelvare@suse.de>8 *9 * Give only processor, motherboard temperatures and fan tachs10 * Very rare chip please let me know if you use it11 *12 * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf13 */14 15#include <linux/module.h>16#include <linux/init.h>17#include <linux/slab.h>18#include <linux/jiffies.h>19#include <linux/i2c.h>20#include <linux/hwmon-sysfs.h>21#include <linux/hwmon.h>22#include <linux/err.h>23#include <linux/mutex.h>24 25/*26 * Addresses to scan27 */28 29static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,30						0x2e, 0x2f, I2C_CLIENT_END31};32 33/*34 * The ADM1029 registers35 * Manufacturer ID is 0x41 for Analog Devices36 */37 38#define ADM1029_REG_MAN_ID			0x0D39#define ADM1029_REG_CHIP_ID			0x0E40#define ADM1029_REG_CONFIG			0x0141#define ADM1029_REG_NB_FAN_SUPPORT		0x0242 43#define ADM1029_REG_TEMP_DEVICES_INSTALLED	0x0644 45#define ADM1029_REG_LOCAL_TEMP			0xA046#define ADM1029_REG_REMOTE1_TEMP		0xA147#define ADM1029_REG_REMOTE2_TEMP		0xA248 49#define ADM1029_REG_LOCAL_TEMP_HIGH		0x9050#define ADM1029_REG_REMOTE1_TEMP_HIGH		0x9151#define ADM1029_REG_REMOTE2_TEMP_HIGH		0x9252 53#define ADM1029_REG_LOCAL_TEMP_LOW		0x9854#define ADM1029_REG_REMOTE1_TEMP_LOW		0x9955#define ADM1029_REG_REMOTE2_TEMP_LOW		0x9A56 57#define ADM1029_REG_FAN1			0x7058#define ADM1029_REG_FAN2			0x7159 60#define ADM1029_REG_FAN1_MIN			0x7861#define ADM1029_REG_FAN2_MIN			0x7962 63#define ADM1029_REG_FAN1_CONFIG			0x6864#define ADM1029_REG_FAN2_CONFIG			0x6965 66#define TEMP_FROM_REG(val)	((val) * 1000)67 68#define DIV_FROM_REG(val)	(1 << (((val) >> 6) - 1))69 70/* Registers to be checked by adm1029_update_device() */71static const u8 ADM1029_REG_TEMP[] = {72	ADM1029_REG_LOCAL_TEMP,73	ADM1029_REG_REMOTE1_TEMP,74	ADM1029_REG_REMOTE2_TEMP,75	ADM1029_REG_LOCAL_TEMP_HIGH,76	ADM1029_REG_REMOTE1_TEMP_HIGH,77	ADM1029_REG_REMOTE2_TEMP_HIGH,78	ADM1029_REG_LOCAL_TEMP_LOW,79	ADM1029_REG_REMOTE1_TEMP_LOW,80	ADM1029_REG_REMOTE2_TEMP_LOW,81};82 83static const u8 ADM1029_REG_FAN[] = {84	ADM1029_REG_FAN1,85	ADM1029_REG_FAN2,86	ADM1029_REG_FAN1_MIN,87	ADM1029_REG_FAN2_MIN,88};89 90static const u8 ADM1029_REG_FAN_DIV[] = {91	ADM1029_REG_FAN1_CONFIG,92	ADM1029_REG_FAN2_CONFIG,93};94 95/*96 * Client data (each client gets its own)97 */98 99struct adm1029_data {100	struct i2c_client *client;101	struct mutex update_lock; /* protect register access */102	bool valid;		/* false until following fields are valid */103	unsigned long last_updated;	/* in jiffies */104 105	/* registers values, signed for temperature, unsigned for other stuff */106	s8 temp[ARRAY_SIZE(ADM1029_REG_TEMP)];107	u8 fan[ARRAY_SIZE(ADM1029_REG_FAN)];108	u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)];109};110 111/*112 * function that update the status of the chips (temperature for example)113 */114static struct adm1029_data *adm1029_update_device(struct device *dev)115{116	struct adm1029_data *data = dev_get_drvdata(dev);117	struct i2c_client *client = data->client;118 119	mutex_lock(&data->update_lock);120	/*121	 * Use the "cache" Luke, don't recheck values122	 * if there are already checked not a long time later123	 */124	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {125		int nr;126 127		dev_dbg(&client->dev, "Updating adm1029 data\n");128 129		for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {130			data->temp[nr] =131			    i2c_smbus_read_byte_data(client,132						     ADM1029_REG_TEMP[nr]);133		}134		for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {135			data->fan[nr] =136			    i2c_smbus_read_byte_data(client,137						     ADM1029_REG_FAN[nr]);138		}139		for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {140			data->fan_div[nr] =141			    i2c_smbus_read_byte_data(client,142						     ADM1029_REG_FAN_DIV[nr]);143		}144 145		data->last_updated = jiffies;146		data->valid = true;147	}148 149	mutex_unlock(&data->update_lock);150 151	return data;152}153 154/*155 * Sysfs stuff156 */157 158static ssize_t159temp_show(struct device *dev, struct device_attribute *devattr, char *buf)160{161	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);162	struct adm1029_data *data = adm1029_update_device(dev);163 164	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));165}166 167static ssize_t168fan_show(struct device *dev, struct device_attribute *devattr, char *buf)169{170	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);171	struct adm1029_data *data = adm1029_update_device(dev);172	u16 val;173 174	if (data->fan[attr->index] == 0 ||175	    (data->fan_div[attr->index] & 0xC0) == 0 ||176	    data->fan[attr->index] == 255) {177		return sprintf(buf, "0\n");178	}179 180	val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])181	    / data->fan[attr->index];182	return sprintf(buf, "%d\n", val);183}184 185static ssize_t186fan_div_show(struct device *dev, struct device_attribute *devattr, char *buf)187{188	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);189	struct adm1029_data *data = adm1029_update_device(dev);190 191	if ((data->fan_div[attr->index] & 0xC0) == 0)192		return sprintf(buf, "0\n");193	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));194}195 196static ssize_t fan_div_store(struct device *dev,197			     struct device_attribute *devattr,198			     const char *buf, size_t count)199{200	struct adm1029_data *data = dev_get_drvdata(dev);201	struct i2c_client *client = data->client;202	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);203	u8 reg;204	long val;205	int ret = kstrtol(buf, 10, &val);206 207	if (ret < 0)208		return ret;209 210	mutex_lock(&data->update_lock);211 212	/*Read actual config */213	reg = i2c_smbus_read_byte_data(client,214				       ADM1029_REG_FAN_DIV[attr->index]);215 216	switch (val) {217	case 1:218		val = 1;219		break;220	case 2:221		val = 2;222		break;223	case 4:224		val = 3;225		break;226	default:227		mutex_unlock(&data->update_lock);228		dev_err(&client->dev,229			"fan_div value %ld not supported. Choose one of 1, 2 or 4!\n",230			val);231		return -EINVAL;232	}233	/* Update the value */234	reg = (reg & 0x3F) | (val << 6);235 236	/* Update the cache */237	data->fan_div[attr->index] = reg;238 239	/* Write value */240	i2c_smbus_write_byte_data(client,241				  ADM1029_REG_FAN_DIV[attr->index], reg);242	mutex_unlock(&data->update_lock);243 244	return count;245}246 247/* Access rights on sysfs. */248static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);249static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);250static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);251 252static SENSOR_DEVICE_ATTR_RO(temp1_max, temp, 3);253static SENSOR_DEVICE_ATTR_RO(temp2_max, temp, 4);254static SENSOR_DEVICE_ATTR_RO(temp3_max, temp, 5);255 256static SENSOR_DEVICE_ATTR_RO(temp1_min, temp, 6);257static SENSOR_DEVICE_ATTR_RO(temp2_min, temp, 7);258static SENSOR_DEVICE_ATTR_RO(temp3_min, temp, 8);259 260static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);261static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);262 263static SENSOR_DEVICE_ATTR_RO(fan1_min, fan, 2);264static SENSOR_DEVICE_ATTR_RO(fan2_min, fan, 3);265 266static SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);267static SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);268 269static struct attribute *adm1029_attrs[] = {270	&sensor_dev_attr_temp1_input.dev_attr.attr,271	&sensor_dev_attr_temp1_min.dev_attr.attr,272	&sensor_dev_attr_temp1_max.dev_attr.attr,273	&sensor_dev_attr_temp2_input.dev_attr.attr,274	&sensor_dev_attr_temp2_min.dev_attr.attr,275	&sensor_dev_attr_temp2_max.dev_attr.attr,276	&sensor_dev_attr_temp3_input.dev_attr.attr,277	&sensor_dev_attr_temp3_min.dev_attr.attr,278	&sensor_dev_attr_temp3_max.dev_attr.attr,279	&sensor_dev_attr_fan1_input.dev_attr.attr,280	&sensor_dev_attr_fan2_input.dev_attr.attr,281	&sensor_dev_attr_fan1_min.dev_attr.attr,282	&sensor_dev_attr_fan2_min.dev_attr.attr,283	&sensor_dev_attr_fan1_div.dev_attr.attr,284	&sensor_dev_attr_fan2_div.dev_attr.attr,285	NULL286};287 288ATTRIBUTE_GROUPS(adm1029);289 290/*291 * Real code292 */293 294/* Return 0 if detection is successful, -ENODEV otherwise */295static int adm1029_detect(struct i2c_client *client,296			  struct i2c_board_info *info)297{298	struct i2c_adapter *adapter = client->adapter;299	u8 man_id, chip_id, temp_devices_installed, nb_fan_support;300 301	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))302		return -ENODEV;303 304	/*305	 * ADM1029 doesn't have CHIP ID, check just MAN ID306	 * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,307	 * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values308	 * documented309	 */310 311	man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);312	chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);313	temp_devices_installed = i2c_smbus_read_byte_data(client,314					ADM1029_REG_TEMP_DEVICES_INSTALLED);315	nb_fan_support = i2c_smbus_read_byte_data(client,316						  ADM1029_REG_NB_FAN_SUPPORT);317	/* 0x41 is Analog Devices */318	if (man_id != 0x41 || (temp_devices_installed & 0xf9) != 0x01 ||319	    nb_fan_support != 0x03)320		return -ENODEV;321 322	if ((chip_id & 0xF0) != 0x00) {323		/*324		 * There are no "official" CHIP ID, so actually325		 * we use Major/Minor revision for that326		 */327		pr_info("Unknown major revision %x, please let us know\n",328			chip_id);329		return -ENODEV;330	}331 332	strscpy(info->type, "adm1029", I2C_NAME_SIZE);333 334	return 0;335}336 337static int adm1029_init_client(struct i2c_client *client)338{339	u8 config;340 341	config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);342	if ((config & 0x10) == 0) {343		i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG,344					  config | 0x10);345	}346	/* recheck config */347	config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);348	if ((config & 0x10) == 0) {349		dev_err(&client->dev, "Initialization failed!\n");350		return 0;351	}352	return 1;353}354 355static int adm1029_probe(struct i2c_client *client)356{357	struct device *dev = &client->dev;358	struct adm1029_data *data;359	struct device *hwmon_dev;360 361	data = devm_kzalloc(dev, sizeof(struct adm1029_data), GFP_KERNEL);362	if (!data)363		return -ENOMEM;364 365	data->client = client;366	mutex_init(&data->update_lock);367 368	/*369	 * Initialize the ADM1029 chip370	 * Check config register371	 */372	if (adm1029_init_client(client) == 0)373		return -ENODEV;374 375	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,376							   data,377							   adm1029_groups);378	return PTR_ERR_OR_ZERO(hwmon_dev);379}380 381static const struct i2c_device_id adm1029_id[] = {382	{ "adm1029" },383	{ }384};385MODULE_DEVICE_TABLE(i2c, adm1029_id);386 387static struct i2c_driver adm1029_driver = {388	.class		= I2C_CLASS_HWMON,389	.driver = {390		.name = "adm1029",391	},392	.probe		= adm1029_probe,393	.id_table	= adm1029_id,394	.detect		= adm1029_detect,395	.address_list	= normal_i2c,396};397 398module_i2c_driver(adm1029_driver);399 400MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");401MODULE_DESCRIPTION("adm1029 driver");402MODULE_LICENSE("GPL v2");403