16c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan/* 26c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * An hwmon driver for the Analog Devices AD7414 36c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * 46c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering 56c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * 66c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * Copyright (c) 2008 PIKA Technologies 76c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * Sean MacLennan <smaclennan@pikatech.com> 86c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * 96c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * Copyright (c) 2008 Spansion Inc. 106c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * Frank Edelhaeuser <frank.edelhaeuser at spansion.com> 116c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * (converted to "new style" I2C driver model, removed checkpatch.pl warnings) 126c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * 136c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * Based on ad7418.c 146c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo at towertech.it> 156c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * 166c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * This program is free software; you can redistribute it and/or modify 176c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * it under the terms of the GNU General Public License as published by 186c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * the Free Software Foundation; either version 2 of the License, or 196c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * (at your option) any later version. 206c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan */ 216c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 226c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/module.h> 236c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/jiffies.h> 246c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/i2c.h> 256c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/hwmon.h> 266c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/hwmon-sysfs.h> 276c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/err.h> 286c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/mutex.h> 296c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#include <linux/sysfs.h> 305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 316c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 326c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 336c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan/* AD7414 registers */ 346c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#define AD7414_REG_TEMP 0x00 356c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#define AD7414_REG_CONF 0x01 366c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#define AD7414_REG_T_HIGH 0x02 376c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan#define AD7414_REG_T_LOW 0x03 386c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 396c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic u8 AD7414_REG_LIMIT[] = { AD7414_REG_T_HIGH, AD7414_REG_T_LOW }; 406c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 416c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstruct ad7414_data { 426c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct device *hwmon_dev; 436c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct mutex lock; /* atomic read data updates */ 446c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan char valid; /* !=0 if following fields are valid */ 456c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan unsigned long next_update; /* In jiffies */ 466c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan s16 temp_input; /* Register values */ 476c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan s8 temps[ARRAY_SIZE(AD7414_REG_LIMIT)]; 486c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan}; 496c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 506c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan/* REG: (0.25C/bit, two's complement) << 6 */ 516c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic inline int ad7414_temp_from_reg(s16 reg) 526c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 538deeac82b3f3e73f50ca7109ea0029764b33874fGuenter Roeck /* 548deeac82b3f3e73f50ca7109ea0029764b33874fGuenter Roeck * use integer division instead of equivalent right shift to 556c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan * guarantee arithmetic shift and preserve the sign 566c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan */ 576c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return ((int)reg / 64) * 250; 586c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 596c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 606c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic inline int ad7414_read(struct i2c_client *client, u8 reg) 616c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 6290f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare if (reg == AD7414_REG_TEMP) 6390f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare return i2c_smbus_read_word_swapped(client, reg); 6490f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare else 656c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return i2c_smbus_read_byte_data(client, reg); 666c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 676c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 686c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value) 696c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 706c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return i2c_smbus_write_byte_data(client, reg, value); 716c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 726c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 73d130d97154f5342973a0fffc0b5a144359273c79Adrian Bunkstatic struct ad7414_data *ad7414_update_device(struct device *dev) 746c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 756c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct i2c_client *client = to_i2c_client(dev); 766c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct ad7414_data *data = i2c_get_clientdata(client); 776c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 786c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan mutex_lock(&data->lock); 796c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 806c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (time_after(jiffies, data->next_update) || !data->valid) { 816c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan int value, i; 826c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 836c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan dev_dbg(&client->dev, "starting ad7414 update\n"); 846c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 856c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan value = ad7414_read(client, AD7414_REG_TEMP); 866c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (value < 0) 876c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan dev_dbg(&client->dev, "AD7414_REG_TEMP err %d\n", 886c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan value); 896c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan else 906c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan data->temp_input = value; 916c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 926c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan for (i = 0; i < ARRAY_SIZE(AD7414_REG_LIMIT); ++i) { 936c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan value = ad7414_read(client, AD7414_REG_LIMIT[i]); 946c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (value < 0) 956c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan dev_dbg(&client->dev, "AD7414 reg %d err %d\n", 966c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan AD7414_REG_LIMIT[i], value); 976c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan else 986c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan data->temps[i] = value; 996c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan } 1006c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1016c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan data->next_update = jiffies + HZ + HZ / 2; 1026c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan data->valid = 1; 1036c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan } 1046c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1056c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan mutex_unlock(&data->lock); 1066c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1076c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return data; 1086c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 1096c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1106c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic ssize_t show_temp_input(struct device *dev, 1116c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct device_attribute *attr, char *buf) 1126c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 1136c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct ad7414_data *data = ad7414_update_device(dev); 1146c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return sprintf(buf, "%d\n", ad7414_temp_from_reg(data->temp_input)); 1156c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 1166c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0); 1176c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1186c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic ssize_t show_max_min(struct device *dev, struct device_attribute *attr, 1196c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan char *buf) 1206c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 1216c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan int index = to_sensor_dev_attr(attr)->index; 1226c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct ad7414_data *data = ad7414_update_device(dev); 1236c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return sprintf(buf, "%d\n", data->temps[index] * 1000); 1246c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 1256c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1266c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic ssize_t set_max_min(struct device *dev, 1276c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct device_attribute *attr, 1286c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan const char *buf, size_t count) 1296c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 1306c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct i2c_client *client = to_i2c_client(dev); 1316c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct ad7414_data *data = i2c_get_clientdata(client); 1326c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan int index = to_sensor_dev_attr(attr)->index; 1336c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan u8 reg = AD7414_REG_LIMIT[index]; 134dcb7cb97bafff6c93b65626634f9c066436bf9d2Frans Meulenbroeks long temp; 135dcb7cb97bafff6c93b65626634f9c066436bf9d2Frans Meulenbroeks int ret = kstrtol(buf, 10, &temp); 136dcb7cb97bafff6c93b65626634f9c066436bf9d2Frans Meulenbroeks 137dcb7cb97bafff6c93b65626634f9c066436bf9d2Frans Meulenbroeks if (ret < 0) 138dcb7cb97bafff6c93b65626634f9c066436bf9d2Frans Meulenbroeks return ret; 1396c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1406c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan temp = SENSORS_LIMIT(temp, -40000, 85000); 1416c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan temp = (temp + (temp < 0 ? -500 : 500)) / 1000; 1426c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1436c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan mutex_lock(&data->lock); 1446c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan data->temps[index] = temp; 1456c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan ad7414_write(client, reg, temp); 1466c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan mutex_unlock(&data->lock); 1476c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return count; 1486c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 1496c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1506c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, 1516c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan show_max_min, set_max_min, 0); 1526c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, 1536c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan show_max_min, set_max_min, 1); 1546c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1556c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic ssize_t show_alarm(struct device *dev, struct device_attribute *attr, 1566c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan char *buf) 1576c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 1586c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan int bitnr = to_sensor_dev_attr(attr)->index; 1596c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct ad7414_data *data = ad7414_update_device(dev); 1606c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan int value = (data->temp_input >> bitnr) & 1; 1616c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return sprintf(buf, "%d\n", value); 1626c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 1636c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1646c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 3); 1656c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 4); 1666c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1676c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic struct attribute *ad7414_attributes[] = { 1686c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan &sensor_dev_attr_temp1_input.dev_attr.attr, 1696c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan &sensor_dev_attr_temp1_max.dev_attr.attr, 1706c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan &sensor_dev_attr_temp1_min.dev_attr.attr, 1716c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 1726c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 1736c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan NULL 1746c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan}; 1756c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1766c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic const struct attribute_group ad7414_group = { 1776c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan .attrs = ad7414_attributes, 1786c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan}; 1796c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1806c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic int ad7414_probe(struct i2c_client *client, 1816c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan const struct i2c_device_id *dev_id) 1826c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 1836c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct ad7414_data *data; 1846c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan int conf; 185f0030d87be3cb2eb9eac633d09cb5d9f107ed0c6Axel Lin int err; 1866c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1876c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | 188f0030d87be3cb2eb9eac633d09cb5d9f107ed0c6Axel Lin I2C_FUNC_SMBUS_READ_WORD_DATA)) { 189f0030d87be3cb2eb9eac633d09cb5d9f107ed0c6Axel Lin err = -EOPNOTSUPP; 1906c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan goto exit; 191f0030d87be3cb2eb9eac633d09cb5d9f107ed0c6Axel Lin } 1926c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1936c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL); 1946c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (!data) { 1956c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan err = -ENOMEM; 1966c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan goto exit; 1976c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan } 1986c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 1996c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan i2c_set_clientdata(client, data); 2006c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan mutex_init(&data->lock); 2016c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2026c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan dev_info(&client->dev, "chip found\n"); 2036c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2046c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan /* Make sure the chip is powered up. */ 2056c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan conf = i2c_smbus_read_byte_data(client, AD7414_REG_CONF); 2066c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (conf < 0) 2076c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan dev_warn(&client->dev, 2086c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan "ad7414_probe unable to read config register.\n"); 2096c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan else { 2106c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan conf &= ~(1 << 7); 2116c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan i2c_smbus_write_byte_data(client, AD7414_REG_CONF, conf); 2126c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan } 2136c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2146c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan /* Register sysfs hooks */ 2156c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan err = sysfs_create_group(&client->dev.kobj, &ad7414_group); 2166c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (err) 2176c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan goto exit_free; 2186c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2196c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan data->hwmon_dev = hwmon_device_register(&client->dev); 2206c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan if (IS_ERR(data->hwmon_dev)) { 2216c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan err = PTR_ERR(data->hwmon_dev); 2226c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan goto exit_remove; 2236c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan } 2246c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2256c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return 0; 2266c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2276c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanexit_remove: 2286c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan sysfs_remove_group(&client->dev.kobj, &ad7414_group); 2296c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanexit_free: 2306c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan kfree(data); 2316c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanexit: 2326c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return err; 2336c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 2346c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2356c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic int __devexit ad7414_remove(struct i2c_client *client) 2366c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan{ 2376c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan struct ad7414_data *data = i2c_get_clientdata(client); 2386c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2396c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan hwmon_device_unregister(data->hwmon_dev); 2406c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan sysfs_remove_group(&client->dev.kobj, &ad7414_group); 2416c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan kfree(data); 2426c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan return 0; 2436c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan} 2446c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2456c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic const struct i2c_device_id ad7414_id[] = { 2466c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan { "ad7414", 0 }, 2476c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan {} 2486c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan}; 2496407deb59466372fd7addca38fa2f44898591897Axel LinMODULE_DEVICE_TABLE(i2c, ad7414_id); 2506c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2516c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanstatic struct i2c_driver ad7414_driver = { 2526c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan .driver = { 2536c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan .name = "ad7414", 2546c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan }, 2556c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan .probe = ad7414_probe, 2566c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan .remove = __devexit_p(ad7414_remove), 2576c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan .id_table = ad7414_id, 2586c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan}; 2596c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 260f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(ad7414_driver); 2616c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2626c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanMODULE_AUTHOR("Stefan Roese <sr at denx.de>, " 2636c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan "Frank Edelhaeuser <frank.edelhaeuser at spansion.com>"); 2646c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennan 2656c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanMODULE_DESCRIPTION("AD7414 driver"); 2666c633c3025c75f5fcf3a76d375faff34e3be021bSean MacLennanMODULE_LICENSE("GPL"); 267