11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * max1619.c - Part of lm_sensors, Linux kernel modules for hardware 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * monitoring 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jean Delvare <khali@linux-fr.org> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It reports up to two temperatures (its own plus up to 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one external one). Complete datasheet can be 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * obtained from Maxim's website at: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h> 34943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h> 3571062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare#include <linux/hwmon-sysfs.h> 36943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h> 379a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h> 38a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare#include <linux/sysfs.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4025e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffmanstatic const unsigned short normal_i2c[] = { 4125e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffman 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The MAX1619 registers 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_MAN_ID 0xFE 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_CHIP_ID 0xFF 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_CONFIG 0x03 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_W_CONFIG 0x09 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_CONVRATE 0x04 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_W_CONVRATE 0x0A 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_STATUS 0x02 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_LOCAL_TEMP 0x00 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_REMOTE_TEMP 0x01 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_REMOTE_HIGH 0x07 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_W_REMOTE_HIGH 0x0D 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_REMOTE_LOW 0x08 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_W_REMOTE_LOW 0x0E 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_REMOTE_CRIT 0x10 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_W_REMOTE_CRIT 0x12 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_R_TCRIT_HYST 0x11 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX1619_REG_W_TCRIT_HYST 0x13 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 66a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton * Conversions 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Mortonstatic int temp_from_reg(int val) 70a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton{ 71a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton return (val & 0x80 ? val-0x100 : val) * 1000; 72a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton} 73a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton 74a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Mortonstatic int temp_to_reg(int val) 75a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton{ 76a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton return (val < 0 ? val+0x100*1000 : val) / 1000; 77a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton} 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Functions declaration 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvarestatic int max1619_probe(struct i2c_client *client, 84c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare const struct i2c_device_id *id); 85310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int max1619_detect(struct i2c_client *client, 86c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare struct i2c_board_info *info); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void max1619_init_client(struct i2c_client *client); 88c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvarestatic int max1619_remove(struct i2c_client *client); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct max1619_data *max1619_update_device(struct device *dev); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver data (common to all clients) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvarestatic const struct i2c_device_id max1619_id[] = { 961f86df49ddfd0067cce941187d57b2fd2f749a9eJean Delvare { "max1619", 0 }, 97c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare { } 98c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare}; 99c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean DelvareMODULE_DEVICE_TABLE(i2c, max1619_id); 100c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_driver max1619_driver = { 102c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare .class = I2C_CLASS_HWMON, 103cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard .driver = { 104cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard .name = "max1619", 105cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard }, 106c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare .probe = max1619_probe, 107c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare .remove = max1619_remove, 108c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare .id_table = max1619_id, 109c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare .detect = max1619_detect, 110c3813d6af177fab19e322f3114b1f64fbcf08d71Jean Delvare .address_list = normal_i2c, 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Client data (each client gets its own) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct max1619_data { 1181beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones struct device *hwmon_dev; 1199a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar struct mutex update_lock; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char valid; /* zero until following fields are valid */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_updated; /* in jiffies */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* registers values */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_input1; /* local */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_input2, temp_low2, temp_high2; /* remote */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_crit2; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_hyst2; 1288958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck u8 alarms; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sysfs stuff 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_temp(value) \ 1368958dfb74a8b8673824d21efabaf565777c549feGuenter Roeckstatic ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ 1378958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck char *buf) \ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct max1619_data *data = max1619_update_device(dev); \ 140a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton return sprintf(buf, "%d\n", temp_from_reg(data->value)); \ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp(temp_input1); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp(temp_input2); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp(temp_low2); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp(temp_high2); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp(temp_crit2); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp(temp_hyst2); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define set_temp2(value, reg) \ 1508958dfb74a8b8673824d21efabaf565777c549feGuenter Roeckstatic ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ 1518958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck const char *buf, \ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t count) \ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); \ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct max1619_data *data = i2c_get_clientdata(client); \ 1568958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck long val; \ 1578958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck int err = kstrtol(buf, 10, &val); \ 1588958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck if (err) \ 1598958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck return err; \ 1608958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck\ 1619a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); \ 162a80e8ee66793ec2e7ce27fd0495a7b9c8e0a2a24Andrew Morton data->value = temp_to_reg(val); \ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2c_smbus_write_byte_data(client, reg, data->value); \ 1649a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); \ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; \ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1738958dfb74a8b8673824d21efabaf565777c549feGuenter Roeckstatic ssize_t show_alarms(struct device *dev, struct device_attribute *attr, 1748958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck char *buf) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct max1619_data *data = max1619_update_device(dev); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%d\n", data->alarms); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18071062ffcd5173b8291ee80e84711b619b34a64ebJean Delvarestatic ssize_t show_alarm(struct device *dev, struct device_attribute *attr, 18171062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare char *buf) 18271062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare{ 18371062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare int bitnr = to_sensor_dev_attr(attr)->index; 18471062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare struct max1619_data *data = max1619_update_device(dev); 18571062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); 18671062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare} 18771062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_temp_low2); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_temp_high2); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_temp_crit2); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_temp_hyst2); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); 19971062ffcd5173b8291ee80e84711b619b34a64ebJean Delvarestatic SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); 20071062ffcd5173b8291ee80e84711b619b34a64ebJean Delvarestatic SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); 20171062ffcd5173b8291ee80e84711b619b34a64ebJean Delvarestatic SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); 20271062ffcd5173b8291ee80e84711b619b34a64ebJean Delvarestatic SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 204a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvarestatic struct attribute *max1619_attributes[] = { 205a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare &dev_attr_temp1_input.attr, 206a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare &dev_attr_temp2_input.attr, 207a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare &dev_attr_temp2_min.attr, 208a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare &dev_attr_temp2_max.attr, 209a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare &dev_attr_temp2_crit.attr, 210a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare &dev_attr_temp2_crit_hyst.attr, 211a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare 212a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare &dev_attr_alarms.attr, 21371062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, 21471062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare &sensor_dev_attr_temp2_fault.dev_attr.attr, 21571062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, 21671062ffcd5173b8291ee80e84711b619b34a64ebJean Delvare &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, 217a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare NULL 218a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare}; 219a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare 220a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvarestatic const struct attribute_group max1619_group = { 221a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare .attrs = max1619_attributes, 222a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare}; 223a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Real code 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 228c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare/* Return 0 if detection is successful, -ENODEV otherwise */ 229310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int max1619_detect(struct i2c_client *client, 230c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare struct i2c_board_info *info) 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare struct i2c_adapter *adapter = client->adapter; 23352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare u8 reg_config, reg_convrate, reg_status, man_id, chip_id; 234b0020e3f526cdbb2eb9408bc1b12171b3b91625bAndrew Morton 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 236c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare return -ENODEV; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare /* detection */ 23952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare reg_config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); 24052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare reg_convrate = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONVRATE); 24152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare reg_status = i2c_smbus_read_byte_data(client, MAX1619_REG_R_STATUS); 24252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if ((reg_config & 0x03) != 0x00 24352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare || reg_convrate > 0x07 || (reg_status & 0x61) != 0x00) { 24452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare dev_dbg(&adapter->dev, "MAX1619 detection failed at 0x%02x\n", 24552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare client->addr); 24652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare return -ENODEV; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare /* identification */ 25052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare man_id = i2c_smbus_read_byte_data(client, MAX1619_REG_R_MAN_ID); 25152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare chip_id = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CHIP_ID); 25252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if (man_id != 0x4D || chip_id != 0x04) { 25352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare dev_info(&adapter->dev, 25452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare "Unsupported chip (man_id=0x%02X, chip_id=0x%02X).\n", 25552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare man_id, chip_id); 25652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare return -ENODEV; 257b0020e3f526cdbb2eb9408bc1b12171b3b91625bAndrew Morton } 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 259c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare strlcpy(info->type, "max1619", I2C_NAME_SIZE); 260c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare 261c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare return 0; 262c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare} 263c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare 264c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvarestatic int max1619_probe(struct i2c_client *new_client, 265c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare const struct i2c_device_id *id) 266c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare{ 267c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare struct max1619_data *data; 268c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare int err; 269c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare 270c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL); 271c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare if (!data) { 272c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare err = -ENOMEM; 273c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare goto exit; 274c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare } 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 276c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare i2c_set_clientdata(new_client, data); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->valid = 0; 2789a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_init(&data->update_lock); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the MAX1619 chip */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max1619_init_client(new_client); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register sysfs hooks */ 2848958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck err = sysfs_create_group(&new_client->dev.kobj, &max1619_group); 2858958dfb74a8b8673824d21efabaf565777c549feGuenter Roeck if (err) 286c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvare goto exit_free; 287a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare 2881beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones data->hwmon_dev = hwmon_device_register(&new_client->dev); 2891beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones if (IS_ERR(data->hwmon_dev)) { 2901beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones err = PTR_ERR(data->hwmon_dev); 291a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare goto exit_remove_files; 292943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman } 293943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 296a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvareexit_remove_files: 297a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare sysfs_remove_group(&new_client->dev.kobj, &max1619_group); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit_free: 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(data); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void max1619_init_client(struct i2c_client *client) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 config; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start the conversions. 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5); /* 2 Hz */ 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (config & 0x40) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds config & 0xBF); /* run */ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 319c6d3f6fa1b0b984991d6e2a261c7dd7f2685c7bdJean Delvarestatic int max1619_remove(struct i2c_client *client) 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 321943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman struct max1619_data *data = i2c_get_clientdata(client); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones hwmon_device_unregister(data->hwmon_dev); 324a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare sysfs_remove_group(&client->dev.kobj, &max1619_group); 325943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman 326943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman kfree(data); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct max1619_data *max1619_update_device(struct device *dev) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct max1619_data *data = i2c_get_clientdata(client); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3359a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&client->dev, "Updating max1619 data.\n"); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_input1 = i2c_smbus_read_byte_data(client, 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX1619_REG_R_LOCAL_TEMP); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_input2 = i2c_smbus_read_byte_data(client, 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX1619_REG_R_REMOTE_TEMP); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_high2 = i2c_smbus_read_byte_data(client, 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX1619_REG_R_REMOTE_HIGH); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_low2 = i2c_smbus_read_byte_data(client, 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX1619_REG_R_REMOTE_LOW); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_crit2 = i2c_smbus_read_byte_data(client, 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX1619_REG_R_REMOTE_CRIT); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_hyst2 = i2c_smbus_read_byte_data(client, 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX1619_REG_R_TCRIT_HYST); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->alarms = i2c_smbus_read_byte_data(client, 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX1619_REG_R_STATUS); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->last_updated = jiffies; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->valid = 1; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3589a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return data; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 363f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(max1619_driver); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 365368609c5a8bd75b77721e69726ddfd3c6a30f7d4Jean DelvareMODULE_AUTHOR("Alexey Fisher <fishor@mail.ru> and " 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Jean Delvare <khali@linux-fr.org>"); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("MAX1619 sensor driver"); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 369