// SPDX-License-Identifier: GPL-2.0-or-later
/*
* adm1025 . c
*
* Copyright ( C ) 2000 Chen - Yuan Wu < gwu @ esoft . com >
* Copyright ( C ) 2003 - 2009 Jean Delvare < jdelvare @ suse . de >
*
* The ADM1025 is a sensor chip made by Analog Devices . It reports up to 6
* voltages ( including its own power source ) and up to two temperatures
* ( its own plus up to one external one ) . Voltages are scaled internally
* ( which is not the common way ) with ratios such that the nominal value
* of each voltage correspond to a register value of 192 ( which means a
* resolution of about 0 . 5 % of the nominal value ) . Temperature values are
* reported with a 1 deg resolution and a 3 deg accuracy . Complete
* datasheet can be obtained from Analog ' s website at :
* https : //www.onsemi.com/PowerSolutions/product.do?id=ADM1025
*
* This driver also supports the ADM1025A , which differs from the ADM1025
* only in that it has " open - drain VID inputs while the ADM1025 has
* on - chip 100 k pull - ups on the VID inputs " . It doesn ' t make any
* difference for us .
*
* This driver also supports the NE1619 , a sensor chip made by Philips .
* That chip is similar to the ADM1025A , with a few differences . The only
* difference that matters to us is that the NE1619 has only two possible
* addresses while the ADM1025A has a third one . Complete datasheet can be
* obtained from Philips ' s website at :
* http : //www.semiconductors.philips.com/pip/NE1619DS.html
*
* Since the ADM1025 was the first chipset supported by this driver , most
* comments will refer to this chipset , but are actually general and
* concern all supported chipsets , unless mentioned otherwise .
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
/*
* Addresses to scan
* ADM1025 and ADM1025A have three possible addresses : 0 x2c , 0 x2d and 0 x2e .
* NE1619 has two possible addresses : 0 x2c and 0 x2d .
*/
static const unsigned short normal_i2c[] = { 0 x2c, 0 x2d, 0 x2e, I2C_CLIENT_END };
enum chips { adm1025, ne1619 };
/*
* The ADM1025 registers
*/
#define ADM1025_REG_MAN_ID 0 x3E
#define ADM1025_REG_CHIP_ID 0 x3F
#define ADM1025_REG_CONFIG 0 x40
#define ADM1025_REG_STATUS1 0 x41
#define ADM1025_REG_STATUS2 0 x42
#define ADM1025_REG_IN(nr) (0 x20 + (nr))
#define ADM1025_REG_IN_MAX(nr) (0 x2B + (nr) * 2 )
#define ADM1025_REG_IN_MIN(nr) (0 x2C + (nr) * 2 )
#define ADM1025_REG_TEMP(nr) (0 x26 + (nr))
#define ADM1025_REG_TEMP_HIGH(nr) (0 x37 + (nr) * 2 )
#define ADM1025_REG_TEMP_LOW(nr) (0 x38 + (nr) * 2 )
#define ADM1025_REG_VID 0 x47
#define ADM1025_REG_VID4 0 x49
/*
* Conversions and various macros
* The ADM1025 uses signed 8 - bit values for temperatures .
*/
static const int in_scale[6 ] = { 2500 , 2250 , 3300 , 5000 , 12000 , 3300 };
#define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96 ) / 192 )
#define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \
(val) >= (scale) * 255 / 192 ? 255 : \
((val) * 192 + (scale) / 2 ) / (scale))
#define TEMP_FROM_REG(reg) ((reg) * 1000 )
#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \
(val) >= 126500 ? 127 : \
(((val) < 0 ? (val) - 500 : \
(val) + 500 ) / 1000 ))
/*
* Client data ( each client gets its own )
*/
struct adm1025_data {
struct i2c_client *client;
const struct attribute_group *groups[3 ];
struct mutex update_lock;
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
u8 in[6 ]; /* register value */
u8 in_max[6 ]; /* register value */
u8 in_min[6 ]; /* register value */
s8 temp[2 ]; /* register value */
s8 temp_min[2 ]; /* register value */
s8 temp_max[2 ]; /* register value */
u16 alarms; /* register values, combined */
u8 vid; /* register values, combined */
u8 vrm;
};
static struct adm1025_data *adm1025_update_device(struct device *dev)
{
struct adm1025_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ * 2 ) || !data->valid) {
int i;
dev_dbg(&client->dev, "Updating data.\n" );
for (i = 0 ; i < 6 ; i++) {
data->in[i] = i2c_smbus_read_byte_data(client,
ADM1025_REG_IN(i));
data->in_min[i] = i2c_smbus_read_byte_data(client,
ADM1025_REG_IN_MIN(i));
data->in_max[i] = i2c_smbus_read_byte_data(client,
ADM1025_REG_IN_MAX(i));
}
for (i = 0 ; i < 2 ; i++) {
data->temp[i] = i2c_smbus_read_byte_data(client,
ADM1025_REG_TEMP(i));
data->temp_min[i] = i2c_smbus_read_byte_data(client,
ADM1025_REG_TEMP_LOW(i));
data->temp_max[i] = i2c_smbus_read_byte_data(client,
ADM1025_REG_TEMP_HIGH(i));
}
data->alarms = i2c_smbus_read_byte_data(client,
ADM1025_REG_STATUS1)
| (i2c_smbus_read_byte_data(client,
ADM1025_REG_STATUS2) << 8 );
data->vid = (i2c_smbus_read_byte_data(client,
ADM1025_REG_VID) & 0 x0f)
| ((i2c_smbus_read_byte_data(client,
ADM1025_REG_VID4) & 0 x01) << 4 );
data->last_updated = jiffies;
data->valid = true ;
}
mutex_unlock(&data->update_lock);
return data;
}
/*
* Sysfs stuff
*/
static ssize_t
in_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n" , IN_FROM_REG(data->in[index],
in_scale[index]));
}
static ssize_t
in_min_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n" , IN_FROM_REG(data->in_min[index],
in_scale[index]));
}
static ssize_t
in_max_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n" , IN_FROM_REG(data->in_max[index],
in_scale[index]));
}
static ssize_t
temp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%d\n" , TEMP_FROM_REG(data->temp[index]));
}
static ssize_t
temp_min_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%d\n" , TEMP_FROM_REG(data->temp_min[index]));
}
static ssize_t
temp_max_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%d\n" , TEMP_FROM_REG(data->temp_max[index]));
}
static ssize_t in_min_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
long val;
int err;
err = kstrtol(buf, 10 , &val);
if (err)
return err;
mutex_lock(&data->update_lock);
data->in_min[index] = IN_TO_REG(val, in_scale[index]);
i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(index),
data->in_min[index]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t in_max_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
long val;
int err;
err = kstrtol(buf, 10 , &val);
if (err)
return err;
mutex_lock(&data->update_lock);
data->in_max[index] = IN_TO_REG(val, in_scale[index]);
i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(index),
data->in_max[index]);
mutex_unlock(&data->update_lock);
return count;
}
static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0 );
static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0 );
static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0 );
static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1 );
static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1 );
static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1 );
static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2 );
static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2 );
static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2 );
static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3 );
static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3 );
static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3 );
static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4 );
static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4 );
static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4 );
static SENSOR_DEVICE_ATTR_RO(in5_input, in, 5 );
static SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5 );
static SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5 );
static ssize_t temp_min_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
long val;
int err;
err = kstrtol(buf, 10 , &val);
if (err)
return err;
mutex_lock(&data->update_lock);
data->temp_min[index] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(index),
data->temp_min[index]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t temp_max_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
int index = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
long val;
int err;
err = kstrtol(buf, 10 , &val);
if (err)
return err;
mutex_lock(&data->update_lock);
data->temp_max[index] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(index),
data->temp_max[index]);
mutex_unlock(&data->update_lock);
return count;
}
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0 );
static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0 );
static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0 );
static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1 );
static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1 );
static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1 );
static ssize_t
alarms_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n" , data->alarms);
}
static DEVICE_ATTR_RO(alarms);
static ssize_t
alarm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int bitnr = to_sensor_dev_attr(attr)->index;
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n" , (data->alarms >> bitnr) & 1 );
}
static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0 );
static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1 );
static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2 );
static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3 );
static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8 );
static SENSOR_DEVICE_ATTR_RO(in5_alarm, alarm, 9 );
static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 5 );
static SENSOR_DEVICE_ATTR_RO(temp2_alarm, alarm, 4 );
static SENSOR_DEVICE_ATTR_RO(temp1_fault, alarm, 14 );
static ssize_t
cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1025_data *data = adm1025_update_device(dev);
return sprintf(buf, "%u\n" , vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR_RO(cpu0_vid);
static ssize_t
vrm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct adm1025_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n" , data->vrm);
}
static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct adm1025_data *data = dev_get_drvdata(dev);
unsigned long val;
int err;
err = kstrtoul(buf, 10 , &val);
if (err)
return err;
if (val > 255 )
return -EINVAL;
data->vrm = val;
return count;
}
static DEVICE_ATTR_RW(vrm);
/*
* Real code
*/
static struct attribute *adm1025_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in5_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in5_max.dev_attr.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_in5_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_fault.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
NULL
};
static const struct attribute_group adm1025_group = {
.attrs = adm1025_attributes,
};
static struct attribute *adm1025_attributes_in4[] = {
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
&sensor_dev_attr_in4_alarm.dev_attr.attr,
NULL
};
static const struct attribute_group adm1025_group_in4 = {
.attrs = adm1025_attributes_in4,
};
/* Return 0 if detection is successful, -ENODEV otherwise */
static int adm1025_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
const char *name;
u8 man_id, chip_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* Check for unused bits */
if ((i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG) & 0 x80)
|| (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0 xC0)
|| (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0 xBC)) {
dev_dbg(&adapter->dev, "ADM1025 detection failed at 0x%02x\n" ,
client->addr);
return -ENODEV;
}
/* Identification */
chip_id = i2c_smbus_read_byte_data(client, ADM1025_REG_CHIP_ID);
if ((chip_id & 0 xF0) != 0 x20)
return -ENODEV;
man_id = i2c_smbus_read_byte_data(client, ADM1025_REG_MAN_ID);
if (man_id == 0 x41)
name = "adm1025" ;
else if (man_id == 0 xA1 && client->addr != 0 x2E)
name = "ne1619" ;
else
return -ENODEV;
strscpy(info->type, name, I2C_NAME_SIZE);
return 0 ;
}
static void adm1025_init_client(struct i2c_client *client)
{
u8 reg;
struct adm1025_data *data = i2c_get_clientdata(client);
int i;
data->vrm = vid_which_vrm();
/*
* Set high limits
* Usually we avoid setting limits on driver init , but it happens
* that the ADM1025 comes with stupid default limits ( all registers
* set to 0 ) . In case the chip has not gone through any limit
* setting yet , we better set the high limits to the max so that
* no alarm triggers .
*/
for (i = 0 ; i < 6 ; i++) {
reg = i2c_smbus_read_byte_data(client,
ADM1025_REG_IN_MAX(i));
if (reg == 0 )
i2c_smbus_write_byte_data(client,
ADM1025_REG_IN_MAX(i),
0 xFF);
}
for (i = 0 ; i < 2 ; i++) {
reg = i2c_smbus_read_byte_data(client,
ADM1025_REG_TEMP_HIGH(i));
if (reg == 0 )
i2c_smbus_write_byte_data(client,
ADM1025_REG_TEMP_HIGH(i),
0 x7F);
}
/*
* Start the conversions
*/
reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
if (!(reg & 0 x01))
i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG,
(reg&0 x7E)|0 x01);
}
static int adm1025_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct adm1025_data *data;
u8 config;
data = devm_kzalloc(dev, sizeof (struct adm1025_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
data->client = client;
mutex_init(&data->update_lock);
/* Initialize the ADM1025 chip */
adm1025_init_client(client);
/* sysfs hooks */
data->groups[0 ] = &adm1025_group;
/* Pin 11 is either in4 (+12V) or VID4 */
config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
if (!(config & 0 x20))
data->groups[1 ] = &adm1025_group_in4;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data, data->groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id adm1025_id[] = {
{ "adm1025" , adm1025 },
{ "ne1619" , ne1619 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adm1025_id);
static struct i2c_driver adm1025_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "adm1025" ,
},
.probe = adm1025_probe,
.id_table = adm1025_id,
.detect = adm1025_detect,
.address_list = normal_i2c,
};
module_i2c_driver(adm1025_driver);
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>" );
MODULE_DESCRIPTION("ADM1025 driver" );
MODULE_LICENSE("GPL" );
Messung V0.5 in Prozent C=96 H=97 G=96
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-09-27)
¤
*© Formatika GbR, Deutschland