162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ds1621.c - Part of lm_sensors, Linux kernel modules for hardware 462306a36Sopenharmony_ci * monitoring 562306a36Sopenharmony_ci * Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23 662306a36Sopenharmony_ci * based on lm75.c by Frodo Looijaard <frodol@dds.nl> 762306a36Sopenharmony_ci * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with 862306a36Sopenharmony_ci * the help of Jean Delvare <jdelvare@suse.de> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * The DS1621 device is a digital temperature/thermometer with 9-bit 1162306a36Sopenharmony_ci * resolution, a thermal alarm output (Tout), and user-defined minimum 1262306a36Sopenharmony_ci * and maximum temperature thresholds (TH and TL). 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The DS1625, DS1631, DS1721, and DS1731 are pin compatible with the DS1621 1562306a36Sopenharmony_ci * and similar in operation, with slight variations as noted in the device 1662306a36Sopenharmony_ci * datasheets (please refer to www.maximintegrated.com for specific 1762306a36Sopenharmony_ci * device information). 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Since the DS1621 was the first chipset supported by this driver, 2062306a36Sopenharmony_ci * most comments will refer to this chipset, but are actually general 2162306a36Sopenharmony_ci * and concern all supported chipsets, unless mentioned otherwise. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/module.h> 2562306a36Sopenharmony_ci#include <linux/init.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci#include <linux/jiffies.h> 2862306a36Sopenharmony_ci#include <linux/i2c.h> 2962306a36Sopenharmony_ci#include <linux/hwmon.h> 3062306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 3162306a36Sopenharmony_ci#include <linux/err.h> 3262306a36Sopenharmony_ci#include <linux/mutex.h> 3362306a36Sopenharmony_ci#include <linux/sysfs.h> 3462306a36Sopenharmony_ci#include <linux/kernel.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* Supported devices */ 3762306a36Sopenharmony_cienum chips { ds1621, ds1625, ds1631, ds1721, ds1731 }; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Insmod parameters */ 4062306a36Sopenharmony_cistatic int polarity = -1; 4162306a36Sopenharmony_cimodule_param(polarity, int, 0); 4262306a36Sopenharmony_ciMODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low"); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * The Configuration/Status register 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * - DS1621: 4862306a36Sopenharmony_ci * 7 6 5 4 3 2 1 0 4962306a36Sopenharmony_ci * |Done|THF |TLF |NVB | X | X |POL |1SHOT| 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * - DS1625: 5262306a36Sopenharmony_ci * 7 6 5 4 3 2 1 0 5362306a36Sopenharmony_ci * |Done|THF |TLF |NVB | 1 | 0 |POL |1SHOT| 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * - DS1631, DS1731: 5662306a36Sopenharmony_ci * 7 6 5 4 3 2 1 0 5762306a36Sopenharmony_ci * |Done|THF |TLF |NVB | R1 | R0 |POL |1SHOT| 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * - DS1721: 6062306a36Sopenharmony_ci * 7 6 5 4 3 2 1 0 6162306a36Sopenharmony_ci * |Done| X | X | U | R1 | R0 |POL |1SHOT| 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * Where: 6462306a36Sopenharmony_ci * - 'X' is Reserved 6562306a36Sopenharmony_ci * - 'U' is Undefined 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci#define DS1621_REG_CONFIG_NVB 0x10 6862306a36Sopenharmony_ci#define DS1621_REG_CONFIG_RESOL 0x0C 6962306a36Sopenharmony_ci#define DS1621_REG_CONFIG_POLARITY 0x02 7062306a36Sopenharmony_ci#define DS1621_REG_CONFIG_1SHOT 0x01 7162306a36Sopenharmony_ci#define DS1621_REG_CONFIG_DONE 0x80 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define DS1621_REG_CONFIG_RESOL_SHIFT 2 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* ds1721 conversion rates: {C/LSB, time(ms), resolution bit setting} */ 7662306a36Sopenharmony_cistatic const unsigned short ds1721_convrates[] = { 7762306a36Sopenharmony_ci 94, /* 9-bits (0.5, 93.75, RES[0..1] = 0 */ 7862306a36Sopenharmony_ci 188, /* 10-bits (0.25, 187.5, RES[0..1] = 1 */ 7962306a36Sopenharmony_ci 375, /* 11-bits (0.125, 375, RES[0..1] = 2 */ 8062306a36Sopenharmony_ci 750, /* 12-bits (0.0625, 750, RES[0..1] = 3 */ 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define DS1621_CONVERSION_MAX 750 8462306a36Sopenharmony_ci#define DS1625_CONVERSION_MAX 500 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define DS1621_TEMP_MAX 125000 8762306a36Sopenharmony_ci#define DS1621_TEMP_MIN (-55000) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* The DS1621 temperature registers */ 9062306a36Sopenharmony_cistatic const u8 DS1621_REG_TEMP[3] = { 9162306a36Sopenharmony_ci 0xAA, /* input, word, RO */ 9262306a36Sopenharmony_ci 0xA2, /* min, word, RW */ 9362306a36Sopenharmony_ci 0xA1, /* max, word, RW */ 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci#define DS1621_REG_CONF 0xAC /* byte, RW */ 9662306a36Sopenharmony_ci#define DS1621_COM_START 0xEE /* no data */ 9762306a36Sopenharmony_ci#define DS1721_COM_START 0x51 /* no data */ 9862306a36Sopenharmony_ci#define DS1621_COM_STOP 0x22 /* no data */ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* The DS1621 configuration register */ 10162306a36Sopenharmony_ci#define DS1621_ALARM_TEMP_HIGH 0x40 10262306a36Sopenharmony_ci#define DS1621_ALARM_TEMP_LOW 0x20 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Conversions */ 10562306a36Sopenharmony_ci#define ALARMS_FROM_REG(val) ((val) & \ 10662306a36Sopenharmony_ci (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* Each client has this additional data */ 10962306a36Sopenharmony_cistruct ds1621_data { 11062306a36Sopenharmony_ci struct i2c_client *client; 11162306a36Sopenharmony_ci struct mutex update_lock; 11262306a36Sopenharmony_ci bool valid; /* true if following fields are valid */ 11362306a36Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 11462306a36Sopenharmony_ci enum chips kind; /* device type */ 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci u16 temp[3]; /* Register values, word */ 11762306a36Sopenharmony_ci u8 conf; /* Register encoding, combined */ 11862306a36Sopenharmony_ci u8 zbits; /* Resolution encoded as number of 11962306a36Sopenharmony_ci * zero bits */ 12062306a36Sopenharmony_ci u16 update_interval; /* Conversion rate in milliseconds */ 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic inline int DS1621_TEMP_FROM_REG(u16 reg) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return DIV_ROUND_CLOSEST(((s16)reg / 16) * 625, 10); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* 12962306a36Sopenharmony_ci * TEMP: 0.001C/bit (-55C to +125C) 13062306a36Sopenharmony_ci * REG: 13162306a36Sopenharmony_ci * - 1621, 1625: 0.5C/bit, 7 zero-bits 13262306a36Sopenharmony_ci * - 1631, 1721, 1731: 0.0625C/bit, 4 zero-bits 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_cistatic inline u16 DS1621_TEMP_TO_REG(long temp, u8 zbits) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci temp = clamp_val(temp, DS1621_TEMP_MIN, DS1621_TEMP_MAX); 13762306a36Sopenharmony_ci temp = DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; 13862306a36Sopenharmony_ci return temp; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void ds1621_init_client(struct ds1621_data *data, 14262306a36Sopenharmony_ci struct i2c_client *client) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci u8 conf, new_conf, sreg, resol; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); 14762306a36Sopenharmony_ci /* switch to continuous conversion mode */ 14862306a36Sopenharmony_ci new_conf &= ~DS1621_REG_CONFIG_1SHOT; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* setup output polarity */ 15162306a36Sopenharmony_ci if (polarity == 0) 15262306a36Sopenharmony_ci new_conf &= ~DS1621_REG_CONFIG_POLARITY; 15362306a36Sopenharmony_ci else if (polarity == 1) 15462306a36Sopenharmony_ci new_conf |= DS1621_REG_CONFIG_POLARITY; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (conf != new_conf) 15762306a36Sopenharmony_ci i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci switch (data->kind) { 16062306a36Sopenharmony_ci case ds1625: 16162306a36Sopenharmony_ci data->update_interval = DS1625_CONVERSION_MAX; 16262306a36Sopenharmony_ci data->zbits = 7; 16362306a36Sopenharmony_ci sreg = DS1621_COM_START; 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci case ds1631: 16662306a36Sopenharmony_ci case ds1721: 16762306a36Sopenharmony_ci case ds1731: 16862306a36Sopenharmony_ci resol = (new_conf & DS1621_REG_CONFIG_RESOL) >> 16962306a36Sopenharmony_ci DS1621_REG_CONFIG_RESOL_SHIFT; 17062306a36Sopenharmony_ci data->update_interval = ds1721_convrates[resol]; 17162306a36Sopenharmony_ci data->zbits = 7 - resol; 17262306a36Sopenharmony_ci sreg = DS1721_COM_START; 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci default: 17562306a36Sopenharmony_ci data->update_interval = DS1621_CONVERSION_MAX; 17662306a36Sopenharmony_ci data->zbits = 7; 17762306a36Sopenharmony_ci sreg = DS1621_COM_START; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* start conversion */ 18262306a36Sopenharmony_ci i2c_smbus_write_byte(client, sreg); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic struct ds1621_data *ds1621_update_client(struct device *dev) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct ds1621_data *data = dev_get_drvdata(dev); 18862306a36Sopenharmony_ci struct i2c_client *client = data->client; 18962306a36Sopenharmony_ci u8 new_conf; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci mutex_lock(&data->update_lock); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (time_after(jiffies, data->last_updated + data->update_interval) || 19462306a36Sopenharmony_ci !data->valid) { 19562306a36Sopenharmony_ci int i; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci dev_dbg(&client->dev, "Starting ds1621 update\n"); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->temp); i++) 20262306a36Sopenharmony_ci data->temp[i] = i2c_smbus_read_word_swapped(client, 20362306a36Sopenharmony_ci DS1621_REG_TEMP[i]); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* reset alarms if necessary */ 20662306a36Sopenharmony_ci new_conf = data->conf; 20762306a36Sopenharmony_ci if (data->temp[0] > data->temp[1]) /* input > min */ 20862306a36Sopenharmony_ci new_conf &= ~DS1621_ALARM_TEMP_LOW; 20962306a36Sopenharmony_ci if (data->temp[0] < data->temp[2]) /* input < max */ 21062306a36Sopenharmony_ci new_conf &= ~DS1621_ALARM_TEMP_HIGH; 21162306a36Sopenharmony_ci if (data->conf != new_conf) 21262306a36Sopenharmony_ci i2c_smbus_write_byte_data(client, DS1621_REG_CONF, 21362306a36Sopenharmony_ci new_conf); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci data->last_updated = jiffies; 21662306a36Sopenharmony_ci data->valid = true; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return data; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *da, 22562306a36Sopenharmony_ci char *buf) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 22862306a36Sopenharmony_ci struct ds1621_data *data = ds1621_update_client(dev); 22962306a36Sopenharmony_ci return sprintf(buf, "%d\n", 23062306a36Sopenharmony_ci DS1621_TEMP_FROM_REG(data->temp[attr->index])); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic ssize_t temp_store(struct device *dev, struct device_attribute *da, 23462306a36Sopenharmony_ci const char *buf, size_t count) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 23762306a36Sopenharmony_ci struct ds1621_data *data = dev_get_drvdata(dev); 23862306a36Sopenharmony_ci long val; 23962306a36Sopenharmony_ci int err; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci err = kstrtol(buf, 10, &val); 24262306a36Sopenharmony_ci if (err) 24362306a36Sopenharmony_ci return err; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci mutex_lock(&data->update_lock); 24662306a36Sopenharmony_ci data->temp[attr->index] = DS1621_TEMP_TO_REG(val, data->zbits); 24762306a36Sopenharmony_ci i2c_smbus_write_word_swapped(data->client, DS1621_REG_TEMP[attr->index], 24862306a36Sopenharmony_ci data->temp[attr->index]); 24962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 25062306a36Sopenharmony_ci return count; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *da, 25462306a36Sopenharmony_ci char *buf) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct ds1621_data *data = ds1621_update_client(dev); 25762306a36Sopenharmony_ci return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf)); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic ssize_t alarm_show(struct device *dev, struct device_attribute *da, 26162306a36Sopenharmony_ci char *buf) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 26462306a36Sopenharmony_ci struct ds1621_data *data = ds1621_update_client(dev); 26562306a36Sopenharmony_ci return sprintf(buf, "%d\n", !!(data->conf & attr->index)); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic ssize_t update_interval_show(struct device *dev, 26962306a36Sopenharmony_ci struct device_attribute *da, char *buf) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct ds1621_data *data = dev_get_drvdata(dev); 27262306a36Sopenharmony_ci return sysfs_emit(buf, "%hu\n", data->update_interval); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic ssize_t update_interval_store(struct device *dev, 27662306a36Sopenharmony_ci struct device_attribute *da, 27762306a36Sopenharmony_ci const char *buf, size_t count) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct ds1621_data *data = dev_get_drvdata(dev); 28062306a36Sopenharmony_ci struct i2c_client *client = data->client; 28162306a36Sopenharmony_ci unsigned long convrate; 28262306a36Sopenharmony_ci s32 err; 28362306a36Sopenharmony_ci int resol = 0; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci err = kstrtoul(buf, 10, &convrate); 28662306a36Sopenharmony_ci if (err) 28762306a36Sopenharmony_ci return err; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Convert rate into resolution bits */ 29062306a36Sopenharmony_ci while (resol < (ARRAY_SIZE(ds1721_convrates) - 1) && 29162306a36Sopenharmony_ci convrate > ds1721_convrates[resol]) 29262306a36Sopenharmony_ci resol++; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 29562306a36Sopenharmony_ci data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); 29662306a36Sopenharmony_ci data->conf &= ~DS1621_REG_CONFIG_RESOL; 29762306a36Sopenharmony_ci data->conf |= (resol << DS1621_REG_CONFIG_RESOL_SHIFT); 29862306a36Sopenharmony_ci i2c_smbus_write_byte_data(client, DS1621_REG_CONF, data->conf); 29962306a36Sopenharmony_ci data->update_interval = ds1721_convrates[resol]; 30062306a36Sopenharmony_ci data->zbits = 7 - resol; 30162306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return count; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(alarms); 30762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(update_interval); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); 31062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, temp, 1); 31162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, temp, 2); 31262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, DS1621_ALARM_TEMP_LOW); 31362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, DS1621_ALARM_TEMP_HIGH); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic struct attribute *ds1621_attributes[] = { 31662306a36Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 31762306a36Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 31862306a36Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 31962306a36Sopenharmony_ci &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 32062306a36Sopenharmony_ci &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 32162306a36Sopenharmony_ci &dev_attr_alarms.attr, 32262306a36Sopenharmony_ci &dev_attr_update_interval.attr, 32362306a36Sopenharmony_ci NULL 32462306a36Sopenharmony_ci}; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic umode_t ds1621_attribute_visible(struct kobject *kobj, 32762306a36Sopenharmony_ci struct attribute *attr, int index) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 33062306a36Sopenharmony_ci struct ds1621_data *data = dev_get_drvdata(dev); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (attr == &dev_attr_update_interval.attr) 33362306a36Sopenharmony_ci if (data->kind == ds1621 || data->kind == ds1625) 33462306a36Sopenharmony_ci /* shhh, we're hiding update_interval */ 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci return attr->mode; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic const struct attribute_group ds1621_group = { 34062306a36Sopenharmony_ci .attrs = ds1621_attributes, 34162306a36Sopenharmony_ci .is_visible = ds1621_attribute_visible 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci__ATTRIBUTE_GROUPS(ds1621); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic const struct i2c_device_id ds1621_id[]; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int ds1621_probe(struct i2c_client *client) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct ds1621_data *data; 35062306a36Sopenharmony_ci struct device *hwmon_dev; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci data = devm_kzalloc(&client->dev, sizeof(struct ds1621_data), 35362306a36Sopenharmony_ci GFP_KERNEL); 35462306a36Sopenharmony_ci if (!data) 35562306a36Sopenharmony_ci return -ENOMEM; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci mutex_init(&data->update_lock); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci data->kind = i2c_match_id(ds1621_id, client)->driver_data; 36062306a36Sopenharmony_ci data->client = client; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* Initialize the DS1621 chip */ 36362306a36Sopenharmony_ci ds1621_init_client(data, client); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, 36662306a36Sopenharmony_ci client->name, data, 36762306a36Sopenharmony_ci ds1621_groups); 36862306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic const struct i2c_device_id ds1621_id[] = { 37262306a36Sopenharmony_ci { "ds1621", ds1621 }, 37362306a36Sopenharmony_ci { "ds1625", ds1625 }, 37462306a36Sopenharmony_ci { "ds1631", ds1631 }, 37562306a36Sopenharmony_ci { "ds1721", ds1721 }, 37662306a36Sopenharmony_ci { "ds1731", ds1731 }, 37762306a36Sopenharmony_ci { } 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ds1621_id); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* This is the driver that will be inserted */ 38262306a36Sopenharmony_cistatic struct i2c_driver ds1621_driver = { 38362306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 38462306a36Sopenharmony_ci .driver = { 38562306a36Sopenharmony_ci .name = "ds1621", 38662306a36Sopenharmony_ci }, 38762306a36Sopenharmony_ci .probe = ds1621_probe, 38862306a36Sopenharmony_ci .id_table = ds1621_id, 38962306a36Sopenharmony_ci}; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cimodule_i2c_driver(ds1621_driver); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ciMODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>"); 39462306a36Sopenharmony_ciMODULE_DESCRIPTION("DS1621 driver"); 39562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 396