1dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal/* 2dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * emc1403.c - SMSC Thermal Driver 3dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * 4dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * Copyright (C) 2008 Intel Corp 5dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * 6dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * 8dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * This program is free software; you can redistribute it and/or modify 9dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * it under the terms of the GNU General Public License as published by 10dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * the Free Software Foundation; version 2 of the License. 11dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * 12dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * This program is distributed in the hope that it will be useful, but 13dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * WITHOUT ANY WARRANTY; without even the implied warranty of 14dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * General Public License for more details. 16dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * 17dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * You should have received a copy of the GNU General Public License along 18dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * with this program; if not, write to the Free Software Foundation, Inc., 19dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * 22dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * TODO 23dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * - cache alarm and critical limit registers 24dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * - add emc1404 support 25dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal */ 26dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 27dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/module.h> 28dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/init.h> 29dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/slab.h> 30dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/i2c.h> 31dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/hwmon.h> 32dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/hwmon-sysfs.h> 33dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/err.h> 34dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/sysfs.h> 35dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#include <linux/mutex.h> 36dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 37dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#define THERMAL_PID_REG 0xfd 38dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#define THERMAL_SMSC_ID_REG 0xfe 39dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal#define THERMAL_REVISION_REG 0xff 40dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 41dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstruct thermal_data { 42dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct device *hwmon_dev; 43dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct mutex mutex; 444bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck /* 454bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck * Cache the hyst value so we don't keep re-reading it. In theory 464bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck * we could cache it forever as nobody else should be writing it. 474bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck */ 48dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal u8 cached_hyst; 49dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal unsigned long hyst_valid; 50dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal}; 51dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 52dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic ssize_t show_temp(struct device *dev, 53dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct device_attribute *attr, char *buf) 54dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 55dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct i2c_client *client = to_i2c_client(dev); 56dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); 57dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int retval = i2c_smbus_read_byte_data(client, sda->index); 58dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 59dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (retval < 0) 60dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return retval; 61dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return sprintf(buf, "%d000\n", retval); 62dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 63dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 64dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic ssize_t show_bit(struct device *dev, 65dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct device_attribute *attr, char *buf) 66dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 67dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct i2c_client *client = to_i2c_client(dev); 68dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); 69dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int retval = i2c_smbus_read_byte_data(client, sda->nr); 70dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 71dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (retval < 0) 72dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return retval; 73dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal retval &= sda->index; 74dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return sprintf(buf, "%d\n", retval ? 1 : 0); 75dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 76dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 77dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic ssize_t store_temp(struct device *dev, 78dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct device_attribute *attr, const char *buf, size_t count) 79dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 80dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); 81dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct i2c_client *client = to_i2c_client(dev); 82dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal unsigned long val; 83dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int retval; 84dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 85179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks if (kstrtoul(buf, 10, &val)) 86dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return -EINVAL; 87dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal retval = i2c_smbus_write_byte_data(client, sda->index, 88dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal DIV_ROUND_CLOSEST(val, 1000)); 89dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (retval < 0) 90dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return retval; 91dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return count; 92dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 93dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 94960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Coxstatic ssize_t store_bit(struct device *dev, 95960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox struct device_attribute *attr, const char *buf, size_t count) 96960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox{ 97960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox struct i2c_client *client = to_i2c_client(dev); 98960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox struct thermal_data *data = i2c_get_clientdata(client); 99960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); 100960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox unsigned long val; 101960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox int retval; 102960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox 103179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks if (kstrtoul(buf, 10, &val)) 104960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox return -EINVAL; 105960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox 106960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox mutex_lock(&data->mutex); 107960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox retval = i2c_smbus_read_byte_data(client, sda->nr); 108960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox if (retval < 0) 109960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox goto fail; 110960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox 111960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox retval &= ~sda->index; 112960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox if (val) 113960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox retval |= sda->index; 114960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox 115960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox retval = i2c_smbus_write_byte_data(client, sda->index, retval); 116960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox if (retval == 0) 117960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox retval = count; 118960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Coxfail: 119960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox mutex_unlock(&data->mutex); 120960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox return retval; 121960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox} 122960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox 123dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic ssize_t show_hyst(struct device *dev, 124dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct device_attribute *attr, char *buf) 125dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 126dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct i2c_client *client = to_i2c_client(dev); 127dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct thermal_data *data = i2c_get_clientdata(client); 128dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); 129dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int retval; 130dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int hyst; 131dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 132dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal retval = i2c_smbus_read_byte_data(client, sda->index); 133dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (retval < 0) 134dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return retval; 135dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 136dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (time_after(jiffies, data->hyst_valid)) { 137dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal hyst = i2c_smbus_read_byte_data(client, 0x21); 138dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (hyst < 0) 139dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return retval; 140dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal data->cached_hyst = hyst; 141dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal data->hyst_valid = jiffies + HZ; 142dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal } 143dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return sprintf(buf, "%d000\n", retval - data->cached_hyst); 144dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 145dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 146dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic ssize_t store_hyst(struct device *dev, 147dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct device_attribute *attr, const char *buf, size_t count) 148dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 149dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct i2c_client *client = to_i2c_client(dev); 150dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct thermal_data *data = i2c_get_clientdata(client); 151dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); 152dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int retval; 153dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int hyst; 154dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal unsigned long val; 155dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 156179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks if (kstrtoul(buf, 10, &val)) 157dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return -EINVAL; 158dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 159dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal mutex_lock(&data->mutex); 160dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal retval = i2c_smbus_read_byte_data(client, sda->index); 161dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (retval < 0) 162dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal goto fail; 163dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 164dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal hyst = val - retval * 1000; 165dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal hyst = DIV_ROUND_CLOSEST(hyst, 1000); 166dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (hyst < 0 || hyst > 255) { 167dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal retval = -ERANGE; 168dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal goto fail; 169dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal } 170dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 171dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal retval = i2c_smbus_write_byte_data(client, 0x21, hyst); 172dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (retval == 0) { 173dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal retval = count; 174dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal data->cached_hyst = hyst; 175dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal data->hyst_valid = jiffies + HZ; 176dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal } 177dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalfail: 178dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal mutex_unlock(&data->mutex); 179dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return retval; 180dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 181dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 182dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal/* 183dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal * Sensors. We pass the actual i2c register to the methods. 184dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal */ 185dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 186dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, 187dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x06); 188dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, 189dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x05); 190dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 191dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x20); 192dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0x00); 193dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, 194dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x36, 0x01); 195dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, 196dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x35, 0x01); 197dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, 198dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x37, 0x01); 199dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, 200dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_hyst, store_hyst, 0x20); 201dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 202dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, 203dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x08); 204dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, 205dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x07); 206dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, 207dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x19); 208dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01); 209dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, 210dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x36, 0x02); 211dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, 212dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x35, 0x02); 213dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, 214dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x37, 0x02); 215dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO | S_IWUSR, 216dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_hyst, store_hyst, 0x19); 217dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 218dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR, 219dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x16); 220dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR, 221dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x15); 222dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR, 223dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_temp, store_temp, 0x1A); 224dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23); 225dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, 226dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x36, 0x04); 227dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, 228dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x35, 0x04); 229dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, 230dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_bit, NULL, 0x37, 0x04); 231dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR, 232dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal show_hyst, store_hyst, 0x1A); 233dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 234960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Coxstatic SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR, 235960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox show_bit, store_bit, 0x03, 0x40); 236960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox 237dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic struct attribute *mid_att_thermal[] = { 238dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_min.dev_attr.attr, 239dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_max.dev_attr.attr, 240dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_crit.dev_attr.attr, 241dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_input.dev_attr.attr, 242dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 243dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 244dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, 245dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, 246dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_min.dev_attr.attr, 247dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_max.dev_attr.attr, 248dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_crit.dev_attr.attr, 249dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_input.dev_attr.attr, 250dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, 251dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, 252dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, 253dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, 254dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_min.dev_attr.attr, 255dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_max.dev_attr.attr, 256dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_crit.dev_attr.attr, 257dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_input.dev_attr.attr, 258dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, 259dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, 260dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, 261dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, 262960f12f4d1eb5ba3c76dc6b57a909a65dd59e1c2Alan Cox &sensor_dev_attr_power_state.dev_attr.attr, 263dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal NULL 264dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal}; 265dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 266dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic const struct attribute_group m_thermal_gr = { 267dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .attrs = mid_att_thermal 268dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal}; 269dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 270dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic int emc1403_detect(struct i2c_client *client, 271dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct i2c_board_info *info) 272dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 273dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int id; 2747a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai /* Check if thermal chip is SMSC and EMC1403 or EMC1423 */ 275dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 276dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG); 277dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (id != 0x5d) 278dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return -ENODEV; 279dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 2807a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); 2817a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai switch (id) { 2827a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai case 0x21: 2837a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai strlcpy(info->type, "emc1403", I2C_NAME_SIZE); 2847a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai break; 2857a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai case 0x23: 2867a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai strlcpy(info->type, "emc1423", I2C_NAME_SIZE); 2877a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai break; 2884bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck /* 2894bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck * Note: 0x25 is the 1404 which is very similar and this 2904bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck * driver could be extended 2914bebced84fb66e8f4c061c5579264b112c39fdecGuenter Roeck */ 2927a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai default: 293dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return -ENODEV; 2947a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai } 295dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 296dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG); 297dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (id != 0x01) 298dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return -ENODEV; 299dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 300dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return 0; 301dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 302dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 303dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic int emc1403_probe(struct i2c_client *client, 304dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal const struct i2c_device_id *id) 305dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 306dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal int res; 307dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct thermal_data *data; 308dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 309dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL); 310dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (data == NULL) { 311dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal dev_warn(&client->dev, "out of memory"); 312dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return -ENOMEM; 313dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal } 314dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 315dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal i2c_set_clientdata(client, data); 316dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal mutex_init(&data->mutex); 317dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal data->hyst_valid = jiffies - 1; /* Expired */ 318dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 319dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr); 320dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (res) { 321dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal dev_warn(&client->dev, "create group failed\n"); 322dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal goto thermal_error1; 323dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal } 324dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal data->hwmon_dev = hwmon_device_register(&client->dev); 325dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal if (IS_ERR(data->hwmon_dev)) { 326dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal res = PTR_ERR(data->hwmon_dev); 327dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal dev_warn(&client->dev, "register hwmon dev failed\n"); 328dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal goto thermal_error2; 329dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal } 330dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal dev_info(&client->dev, "EMC1403 Thermal chip found\n"); 331dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return res; 332dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 333dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalthermal_error2: 334dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal sysfs_remove_group(&client->dev.kobj, &m_thermal_gr); 335dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalthermal_error1: 336dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal kfree(data); 337dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return res; 338dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 339dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 340dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic int emc1403_remove(struct i2c_client *client) 341dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal{ 342dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal struct thermal_data *data = i2c_get_clientdata(client); 343dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 344dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal hwmon_device_unregister(data->hwmon_dev); 345dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal sysfs_remove_group(&client->dev.kobj, &m_thermal_gr); 346dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal kfree(data); 347dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal return 0; 348dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal} 349dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 350dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic const unsigned short emc1403_address_list[] = { 351bcf721d14d881da86a8defa96bdc9492abe191aeGuenter Roeck 0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END 352dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal}; 353dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 354dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic const struct i2c_device_id emc1403_idtable[] = { 355dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal { "emc1403", 0 }, 3567a1b76f2a46016809c7bcacf81e89948cc306703Jekyll Lai { "emc1423", 0 }, 357dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal { } 358dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal}; 359dac6831e67e90d1cee430a66e7390e753c20d835Kalhan TrisalMODULE_DEVICE_TABLE(i2c, emc1403_idtable); 360dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 361dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisalstatic struct i2c_driver sensor_emc1403 = { 362dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .class = I2C_CLASS_HWMON, 363dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .driver = { 364dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .name = "emc1403", 365dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal }, 366dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .detect = emc1403_detect, 367dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .probe = emc1403_probe, 368dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .remove = emc1403_remove, 369dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .id_table = emc1403_idtable, 370dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal .address_list = emc1403_address_list, 371dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal}; 372dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 373f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(sensor_emc1403); 374dac6831e67e90d1cee430a66e7390e753c20d835Kalhan Trisal 375dac6831e67e90d1cee430a66e7390e753c20d835Kalhan TrisalMODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); 376dac6831e67e90d1cee430a66e7390e753c20d835Kalhan TrisalMODULE_DESCRIPTION("emc1403 Thermal Driver"); 377dac6831e67e90d1cee430a66e7390e753c20d835Kalhan TrisalMODULE_LICENSE("GPL v2"); 378