16099469805c24af14250e182bb9ca082b8a6b716Roland Stigge/* 26099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * ds620.c - Support for temperature sensor and thermostat DS620 36099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 46099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de> 56099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 66099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * based on ds1621.c by Christian W. Zuckschwerdt <zany@triq.net> 76099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 86099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * This program is free software; you can redistribute it and/or modify 96099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * it under the terms of the GNU General Public License as published by 106099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * the Free Software Foundation; either version 2 of the License, or 116099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * (at your option) any later version. 126099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 136099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * This program is distributed in the hope that it will be useful, 146099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * but WITHOUT ANY WARRANTY; without even the implied warranty of 156099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 166099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * GNU General Public License for more details. 176099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 186099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * You should have received a copy of the GNU General Public License 196099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * along with this program; if not, write to the Free Software 206099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 216099469805c24af14250e182bb9ca082b8a6b716Roland Stigge */ 226099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 236099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/module.h> 246099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/init.h> 256099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/slab.h> 266099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/jiffies.h> 276099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/i2c.h> 286099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/hwmon.h> 296099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/hwmon-sysfs.h> 306099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/err.h> 316099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/mutex.h> 326099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/sysfs.h> 336099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#include <linux/i2c/ds620.h> 346099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 356099469805c24af14250e182bb9ca082b8a6b716Roland Stigge/* 366099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * Many DS620 constants specified below 376099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 15 14 13 12 11 10 09 08 386099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * |Done|NVB |THF |TLF |R1 |R0 |AUTOC|1SHOT| 396099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 406099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * 07 06 05 04 03 02 01 00 416099469805c24af14250e182bb9ca082b8a6b716Roland Stigge * |PO2 |PO1 |A2 |A1 |A0 | | | | 426099469805c24af14250e182bb9ca082b8a6b716Roland Stigge */ 436099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_DONE 0x8000 446099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_NVB 0x4000 456099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_THF 0x2000 466099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_TLF 0x1000 476099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_R1 0x0800 486099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_R0 0x0400 496099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_AUTOC 0x0200 506099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_1SHOT 0x0100 516099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_PO2 0x0080 526099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_PO1 0x0040 536099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_A2 0x0020 546099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_A1 0x0010 556099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONFIG_A0 0x0008 566099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 576099469805c24af14250e182bb9ca082b8a6b716Roland Stigge/* The DS620 registers */ 586099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic const u8 DS620_REG_TEMP[3] = { 596099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 0xAA, /* input, word, RO */ 606099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 0xA2, /* min, word, RW */ 616099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 0xA0, /* max, word, RW */ 626099469805c24af14250e182bb9ca082b8a6b716Roland Stigge}; 636099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 646099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_REG_CONF 0xAC /* word, RW */ 656099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_COM_START 0x51 /* no data */ 666099469805c24af14250e182bb9ca082b8a6b716Roland Stigge#define DS620_COM_STOP 0x22 /* no data */ 676099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 686099469805c24af14250e182bb9ca082b8a6b716Roland Stigge/* Each client has this additional data */ 696099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestruct ds620_data { 706099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct device *hwmon_dev; 716099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct mutex update_lock; 726099469805c24af14250e182bb9ca082b8a6b716Roland Stigge char valid; /* !=0 if following fields are valid */ 736099469805c24af14250e182bb9ca082b8a6b716Roland Stigge unsigned long last_updated; /* In jiffies */ 746099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 75cc41d586e8b4d76164fe7731c1c49be6cc5fc7e6Roland Stigge s16 temp[3]; /* Register values, word */ 766099469805c24af14250e182bb9ca082b8a6b716Roland Stigge}; 776099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 786099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic void ds620_init_client(struct i2c_client *client) 796099469805c24af14250e182bb9ca082b8a6b716Roland Stigge{ 806099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_platform_data *ds620_info = client->dev.platform_data; 816099469805c24af14250e182bb9ca082b8a6b716Roland Stigge u16 conf, new_conf; 826099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 836099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf = conf = 8490f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare i2c_smbus_read_word_swapped(client, DS620_REG_CONF); 856099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 866099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* switch to continuous conversion mode */ 876099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf &= ~DS620_REG_CONFIG_1SHOT; 886099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* already high at power-on, but don't trust the BIOS! */ 896099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf |= DS620_REG_CONFIG_PO2; 906099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* thermostat mode according to platform data */ 916099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (ds620_info && ds620_info->pomode == 1) 926099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */ 936099469805c24af14250e182bb9ca082b8a6b716Roland Stigge else if (ds620_info && ds620_info->pomode == 2) 946099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */ 956099469805c24af14250e182bb9ca082b8a6b716Roland Stigge else 966099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */ 976099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* with highest precision */ 986099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0; 996099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1006099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (conf != new_conf) 10190f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare i2c_smbus_write_word_swapped(client, DS620_REG_CONF, new_conf); 1026099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1036099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* start conversion */ 1046099469805c24af14250e182bb9ca082b8a6b716Roland Stigge i2c_smbus_write_byte(client, DS620_COM_START); 1056099469805c24af14250e182bb9ca082b8a6b716Roland Stigge} 1066099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1076099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic struct ds620_data *ds620_update_client(struct device *dev) 1086099469805c24af14250e182bb9ca082b8a6b716Roland Stigge{ 1096099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct i2c_client *client = to_i2c_client(dev); 1106099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_data *data = i2c_get_clientdata(client); 1116099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_data *ret = data; 1126099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1136099469805c24af14250e182bb9ca082b8a6b716Roland Stigge mutex_lock(&data->update_lock); 1146099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1156099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 1166099469805c24af14250e182bb9ca082b8a6b716Roland Stigge || !data->valid) { 1176099469805c24af14250e182bb9ca082b8a6b716Roland Stigge int i; 1186099469805c24af14250e182bb9ca082b8a6b716Roland Stigge int res; 1196099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1206099469805c24af14250e182bb9ca082b8a6b716Roland Stigge dev_dbg(&client->dev, "Starting ds620 update\n"); 1216099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1226099469805c24af14250e182bb9ca082b8a6b716Roland Stigge for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 12390f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare res = i2c_smbus_read_word_swapped(client, 12490f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare DS620_REG_TEMP[i]); 1256099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (res < 0) { 1266099469805c24af14250e182bb9ca082b8a6b716Roland Stigge ret = ERR_PTR(res); 1276099469805c24af14250e182bb9ca082b8a6b716Roland Stigge goto abort; 1286099469805c24af14250e182bb9ca082b8a6b716Roland Stigge } 1296099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1306099469805c24af14250e182bb9ca082b8a6b716Roland Stigge data->temp[i] = res; 1316099469805c24af14250e182bb9ca082b8a6b716Roland Stigge } 1326099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1336099469805c24af14250e182bb9ca082b8a6b716Roland Stigge data->last_updated = jiffies; 1346099469805c24af14250e182bb9ca082b8a6b716Roland Stigge data->valid = 1; 1356099469805c24af14250e182bb9ca082b8a6b716Roland Stigge } 1366099469805c24af14250e182bb9ca082b8a6b716Roland Stiggeabort: 1376099469805c24af14250e182bb9ca082b8a6b716Roland Stigge mutex_unlock(&data->update_lock); 1386099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1396099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return ret; 1406099469805c24af14250e182bb9ca082b8a6b716Roland Stigge} 1416099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1426099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic ssize_t show_temp(struct device *dev, struct device_attribute *da, 1436099469805c24af14250e182bb9ca082b8a6b716Roland Stigge char *buf) 1446099469805c24af14250e182bb9ca082b8a6b716Roland Stigge{ 1456099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 1466099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_data *data = ds620_update_client(dev); 1476099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1486099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (IS_ERR(data)) 1496099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return PTR_ERR(data); 1506099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1516099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return sprintf(buf, "%d\n", ((data->temp[attr->index] / 8) * 625) / 10); 1526099469805c24af14250e182bb9ca082b8a6b716Roland Stigge} 1536099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1546099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic ssize_t set_temp(struct device *dev, struct device_attribute *da, 1556099469805c24af14250e182bb9ca082b8a6b716Roland Stigge const char *buf, size_t count) 1566099469805c24af14250e182bb9ca082b8a6b716Roland Stigge{ 1576099469805c24af14250e182bb9ca082b8a6b716Roland Stigge int res; 1586099469805c24af14250e182bb9ca082b8a6b716Roland Stigge long val; 1596099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1606099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 1616099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct i2c_client *client = to_i2c_client(dev); 1626099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_data *data = i2c_get_clientdata(client); 1636099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 164179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks res = kstrtol(buf, 10, &val); 1656099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1666099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (res) 1676099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return res; 1686099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1696099469805c24af14250e182bb9ca082b8a6b716Roland Stigge val = (val * 10 / 625) * 8; 1706099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1716099469805c24af14250e182bb9ca082b8a6b716Roland Stigge mutex_lock(&data->update_lock); 1726099469805c24af14250e182bb9ca082b8a6b716Roland Stigge data->temp[attr->index] = val; 17390f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare i2c_smbus_write_word_swapped(client, DS620_REG_TEMP[attr->index], 17490f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare data->temp[attr->index]); 1756099469805c24af14250e182bb9ca082b8a6b716Roland Stigge mutex_unlock(&data->update_lock); 1766099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return count; 1776099469805c24af14250e182bb9ca082b8a6b716Roland Stigge} 1786099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1796099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic ssize_t show_alarm(struct device *dev, struct device_attribute *da, 1806099469805c24af14250e182bb9ca082b8a6b716Roland Stigge char *buf) 1816099469805c24af14250e182bb9ca082b8a6b716Roland Stigge{ 1826099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 1836099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_data *data = ds620_update_client(dev); 1846099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct i2c_client *client = to_i2c_client(dev); 1856099469805c24af14250e182bb9ca082b8a6b716Roland Stigge u16 conf, new_conf; 1866099469805c24af14250e182bb9ca082b8a6b716Roland Stigge int res; 1876099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1886099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (IS_ERR(data)) 1896099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return PTR_ERR(data); 1906099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 1916099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* reset alarms if necessary */ 19290f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare res = i2c_smbus_read_word_swapped(client, DS620_REG_CONF); 1936099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (res < 0) 1946099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return res; 1956099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 19690f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare new_conf = conf = res; 1976099469805c24af14250e182bb9ca082b8a6b716Roland Stigge new_conf &= ~attr->index; 1986099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (conf != new_conf) { 19990f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare res = i2c_smbus_write_word_swapped(client, DS620_REG_CONF, 20090f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare new_conf); 2016099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (res < 0) 2026099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return res; 2036099469805c24af14250e182bb9ca082b8a6b716Roland Stigge } 2046099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2056099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return sprintf(buf, "%d\n", !!(conf & attr->index)); 2066099469805c24af14250e182bb9ca082b8a6b716Roland Stigge} 2076099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2086099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); 2096099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1); 2106099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2); 2116099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 2126099469805c24af14250e182bb9ca082b8a6b716Roland Stigge DS620_REG_CONFIG_TLF); 2136099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 2146099469805c24af14250e182bb9ca082b8a6b716Roland Stigge DS620_REG_CONFIG_THF); 2156099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2166099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic struct attribute *ds620_attributes[] = { 2176099469805c24af14250e182bb9ca082b8a6b716Roland Stigge &sensor_dev_attr_temp1_input.dev_attr.attr, 2186099469805c24af14250e182bb9ca082b8a6b716Roland Stigge &sensor_dev_attr_temp1_min.dev_attr.attr, 2196099469805c24af14250e182bb9ca082b8a6b716Roland Stigge &sensor_dev_attr_temp1_max.dev_attr.attr, 2206099469805c24af14250e182bb9ca082b8a6b716Roland Stigge &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 2216099469805c24af14250e182bb9ca082b8a6b716Roland Stigge &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 2226099469805c24af14250e182bb9ca082b8a6b716Roland Stigge NULL 2236099469805c24af14250e182bb9ca082b8a6b716Roland Stigge}; 2246099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2256099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic const struct attribute_group ds620_group = { 2266099469805c24af14250e182bb9ca082b8a6b716Roland Stigge .attrs = ds620_attributes, 2276099469805c24af14250e182bb9ca082b8a6b716Roland Stigge}; 2286099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2296099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic int ds620_probe(struct i2c_client *client, 2306099469805c24af14250e182bb9ca082b8a6b716Roland Stigge const struct i2c_device_id *id) 2316099469805c24af14250e182bb9ca082b8a6b716Roland Stigge{ 2326099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_data *data; 2336099469805c24af14250e182bb9ca082b8a6b716Roland Stigge int err; 2346099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2356099469805c24af14250e182bb9ca082b8a6b716Roland Stigge data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL); 2366099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (!data) { 2376099469805c24af14250e182bb9ca082b8a6b716Roland Stigge err = -ENOMEM; 2386099469805c24af14250e182bb9ca082b8a6b716Roland Stigge goto exit; 2396099469805c24af14250e182bb9ca082b8a6b716Roland Stigge } 2406099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2416099469805c24af14250e182bb9ca082b8a6b716Roland Stigge i2c_set_clientdata(client, data); 2426099469805c24af14250e182bb9ca082b8a6b716Roland Stigge mutex_init(&data->update_lock); 2436099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2446099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* Initialize the DS620 chip */ 2456099469805c24af14250e182bb9ca082b8a6b716Roland Stigge ds620_init_client(client); 2466099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2476099469805c24af14250e182bb9ca082b8a6b716Roland Stigge /* Register sysfs hooks */ 2486099469805c24af14250e182bb9ca082b8a6b716Roland Stigge err = sysfs_create_group(&client->dev.kobj, &ds620_group); 2496099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (err) 2506099469805c24af14250e182bb9ca082b8a6b716Roland Stigge goto exit_free; 2516099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2526099469805c24af14250e182bb9ca082b8a6b716Roland Stigge data->hwmon_dev = hwmon_device_register(&client->dev); 2536099469805c24af14250e182bb9ca082b8a6b716Roland Stigge if (IS_ERR(data->hwmon_dev)) { 2546099469805c24af14250e182bb9ca082b8a6b716Roland Stigge err = PTR_ERR(data->hwmon_dev); 2556099469805c24af14250e182bb9ca082b8a6b716Roland Stigge goto exit_remove_files; 2566099469805c24af14250e182bb9ca082b8a6b716Roland Stigge } 2576099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2586099469805c24af14250e182bb9ca082b8a6b716Roland Stigge dev_info(&client->dev, "temperature sensor found\n"); 2596099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2606099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return 0; 2616099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2626099469805c24af14250e182bb9ca082b8a6b716Roland Stiggeexit_remove_files: 2636099469805c24af14250e182bb9ca082b8a6b716Roland Stigge sysfs_remove_group(&client->dev.kobj, &ds620_group); 2646099469805c24af14250e182bb9ca082b8a6b716Roland Stiggeexit_free: 2656099469805c24af14250e182bb9ca082b8a6b716Roland Stigge kfree(data); 2666099469805c24af14250e182bb9ca082b8a6b716Roland Stiggeexit: 2676099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return err; 2686099469805c24af14250e182bb9ca082b8a6b716Roland Stigge} 2696099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2706099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic int ds620_remove(struct i2c_client *client) 2716099469805c24af14250e182bb9ca082b8a6b716Roland Stigge{ 2726099469805c24af14250e182bb9ca082b8a6b716Roland Stigge struct ds620_data *data = i2c_get_clientdata(client); 2736099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2746099469805c24af14250e182bb9ca082b8a6b716Roland Stigge hwmon_device_unregister(data->hwmon_dev); 2756099469805c24af14250e182bb9ca082b8a6b716Roland Stigge sysfs_remove_group(&client->dev.kobj, &ds620_group); 2766099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2776099469805c24af14250e182bb9ca082b8a6b716Roland Stigge kfree(data); 2786099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2796099469805c24af14250e182bb9ca082b8a6b716Roland Stigge return 0; 2806099469805c24af14250e182bb9ca082b8a6b716Roland Stigge} 2816099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2826099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic const struct i2c_device_id ds620_id[] = { 2836099469805c24af14250e182bb9ca082b8a6b716Roland Stigge {"ds620", 0}, 2846099469805c24af14250e182bb9ca082b8a6b716Roland Stigge {} 2856099469805c24af14250e182bb9ca082b8a6b716Roland Stigge}; 2866099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2876099469805c24af14250e182bb9ca082b8a6b716Roland StiggeMODULE_DEVICE_TABLE(i2c, ds620_id); 2886099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 2896099469805c24af14250e182bb9ca082b8a6b716Roland Stigge/* This is the driver that will be inserted */ 2906099469805c24af14250e182bb9ca082b8a6b716Roland Stiggestatic struct i2c_driver ds620_driver = { 2916099469805c24af14250e182bb9ca082b8a6b716Roland Stigge .class = I2C_CLASS_HWMON, 2926099469805c24af14250e182bb9ca082b8a6b716Roland Stigge .driver = { 2936099469805c24af14250e182bb9ca082b8a6b716Roland Stigge .name = "ds620", 2946099469805c24af14250e182bb9ca082b8a6b716Roland Stigge }, 2956099469805c24af14250e182bb9ca082b8a6b716Roland Stigge .probe = ds620_probe, 2966099469805c24af14250e182bb9ca082b8a6b716Roland Stigge .remove = ds620_remove, 2976099469805c24af14250e182bb9ca082b8a6b716Roland Stigge .id_table = ds620_id, 2986099469805c24af14250e182bb9ca082b8a6b716Roland Stigge}; 2996099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 300f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(ds620_driver); 3016099469805c24af14250e182bb9ca082b8a6b716Roland Stigge 3026099469805c24af14250e182bb9ca082b8a6b716Roland StiggeMODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); 3036099469805c24af14250e182bb9ca082b8a6b716Roland StiggeMODULE_DESCRIPTION("DS620 driver"); 3046099469805c24af14250e182bb9ca082b8a6b716Roland StiggeMODULE_LICENSE("GPL"); 305