159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/*
27cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * smsc47m192.c - Support for hardware monitoring block of
37cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck *		  SMSC LPC47M192 and compatible Super I/O chips
47cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck *
57cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * Copyright (C) 2006  Hartmut Rick <linux@rick.claranet.de>
67cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck *
77cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * Derived from lm78.c and other chip drivers.
87cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck *
97cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * This program is free software; you can redistribute it and/or modify
107cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * it under the terms of the GNU General Public License as published by
117cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * the Free Software Foundation; either version 2 of the License, or
127cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * (at your option) any later version.
137cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck *
147cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * This program is distributed in the hope that it will be useful,
157cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of
167cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
177cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * GNU General Public License for more details.
187cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck *
197cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * You should have received a copy of the GNU General Public License
207cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * along with this program; if not, write to the Free Software
217cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
227cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck */
2359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
2459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/module.h>
2559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/init.h>
2659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/slab.h>
2759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/jiffies.h>
2859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/i2c.h>
2959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/hwmon.h>
3059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/hwmon-sysfs.h>
3159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/hwmon-vid.h>
3259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#include <linux/err.h>
33ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare#include <linux/sysfs.h>
34e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare#include <linux/mutex.h>
3559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
3659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* Addresses to scan */
3725e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffmanstatic const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
3859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
3959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* SMSC47M192 registers */
407cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck#define SMSC47M192_REG_IN(nr)		((nr) < 6 ? (0x20 + (nr)) : \
4159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick					(0x50 + (nr) - 6))
427cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck#define SMSC47M192_REG_IN_MAX(nr)	((nr) < 6 ? (0x2b + (nr) * 2) : \
4359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick					(0x54 + (((nr) - 6) * 2)))
447cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck#define SMSC47M192_REG_IN_MIN(nr)	((nr) < 6 ? (0x2c + (nr) * 2) : \
4559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick					(0x55 + (((nr) - 6) * 2)))
4659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic u8 SMSC47M192_REG_TEMP[3] =	{ 0x27, 0x26, 0x52 };
4759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic u8 SMSC47M192_REG_TEMP_MAX[3] =	{ 0x39, 0x37, 0x58 };
4859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic u8 SMSC47M192_REG_TEMP_MIN[3] =	{ 0x3A, 0x38, 0x59 };
497cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck#define SMSC47M192_REG_TEMP_OFFSET(nr)	((nr) == 2 ? 0x1e : 0x1f)
5059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_ALARM1		0x41
5159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_ALARM2		0x42
5259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_VID		0x47
5359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_VID4		0x49
5459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_CONFIG		0x40
5559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_SFR		0x4f
5659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_COMPANY_ID	0x3e
5759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define SMSC47M192_REG_VERSION		0x3f
5859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
5959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* generalised scaling with integer rounding */
6059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic inline int SCALE(long val, int mul, int div)
6159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
6259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	if (val < 0)
6359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		return (val * mul - div / 2) / div;
6459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	else
6559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		return (val * mul + div / 2) / div;
6659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
6759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
6859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* Conversions */
6959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
7059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* smsc47m192 internally scales voltage measurements */
7159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 };
7259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
7359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic inline unsigned int IN_FROM_REG(u8 reg, int n)
7459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
7559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return SCALE(reg, nom_mv[n], 192);
7659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
7759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
7859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic inline u8 IN_TO_REG(unsigned long val, int n)
7959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
8059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
8159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
8259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
837cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck/*
847cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * TEMP: 0.001 degC units (-128C to +127C)
857cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck * REG: 1C/bit, two's complement
867cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck */
8759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic inline s8 TEMP_TO_REG(int val)
8859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
8959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);
9059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
9159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
9259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic inline int TEMP_FROM_REG(s8 val)
9359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
9459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return val * 1000;
9559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
9659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
9759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstruct smsc47m192_data {
981beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	struct device *hwmon_dev;
99e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	struct mutex update_lock;
10059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	char valid;		/* !=0 if following fields are valid */
10159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	unsigned long last_updated;	/* In jiffies */
10259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
10359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 in[8];		/* Register value */
10459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 in_max[8];		/* Register value */
10559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 in_min[8];		/* Register value */
10659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	s8 temp[3];		/* Register value */
10759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	s8 temp_max[3];		/* Register value */
10859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	s8 temp_min[3];		/* Register value */
10959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	s8 temp_offset[3];	/* Register value */
11059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u16 alarms;		/* Register encoding, combined */
11159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 vid;			/* Register encoding, combined */
11259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 vrm;
11359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick};
11459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
1158fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvarestatic int smsc47m192_probe(struct i2c_client *client,
1168fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare			    const struct i2c_device_id *id);
117310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int smsc47m192_detect(struct i2c_client *client,
1188fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare			     struct i2c_board_info *info);
1198fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvarestatic int smsc47m192_remove(struct i2c_client *client);
12059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
12159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
1228fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvarestatic const struct i2c_device_id smsc47m192_id[] = {
1231f86df49ddfd0067cce941187d57b2fd2f749a9eJean Delvare	{ "smsc47m192", 0 },
1248fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	{ }
1258fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare};
1268fb597bb6ec80d53836229bf3576c7b848b909e3Jean DelvareMODULE_DEVICE_TABLE(i2c, smsc47m192_id);
1278fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare
12859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic struct i2c_driver smsc47m192_driver = {
1298fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	.class		= I2C_CLASS_HWMON,
13059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	.driver = {
13159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		.name	= "smsc47m192",
13259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	},
1338fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	.probe		= smsc47m192_probe,
1348fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	.remove		= smsc47m192_remove,
1358fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	.id_table	= smsc47m192_id,
1368fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	.detect		= smsc47m192_detect,
137c3813d6af177fab19e322f3114b1f64fbcf08d71Jean Delvare	.address_list	= normal_i2c,
13859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick};
13959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
14059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* Voltages */
14159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_in(struct device *dev, struct device_attribute *attr,
14259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
14359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
14459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
14559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
14659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
14759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
14859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
14959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
15059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
15159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
15259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
15359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
15459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
15559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
15659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
15759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
15859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
15959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
16059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
16159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
16259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
16359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
16459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
16559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
16659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
16759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
16859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
16959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		const char *buf, size_t count)
17059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
17159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
17259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
17359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct i2c_client *client = to_i2c_client(dev);
17459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = i2c_get_clientdata(client);
1757cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	unsigned long val;
1767cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	int err;
1777cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck
1787cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	err = kstrtoul(buf, 10, &val);
1797cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (err)
1807cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		return err;
18159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
182e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_lock(&data->update_lock);
18359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	data->in_min[nr] = IN_TO_REG(val, nr);
18459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
18559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick							data->in_min[nr]);
186e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_unlock(&data->update_lock);
18759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return count;
18859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
18959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
19059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
19159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		const char *buf, size_t count)
19259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
19359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
19459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
19559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct i2c_client *client = to_i2c_client(dev);
19659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = i2c_get_clientdata(client);
1977cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	unsigned long val;
1987cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	int err;
1997cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck
2007cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	err = kstrtoul(buf, 10, &val);
2017cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (err)
2027cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		return err;
20359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
204e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_lock(&data->update_lock);
20559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	data->in_max[nr] = IN_TO_REG(val, nr);
20659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
20759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick							data->in_max[nr]);
208e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_unlock(&data->update_lock);
20959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return count;
21059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
21159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
21259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define show_in_offset(offset)					\
21359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
21459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		show_in, NULL, offset);				\
21559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
21659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		show_in_min, set_in_min, offset);		\
21759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
21859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		show_in_max, set_in_max, offset);
21959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
22059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(0)
22159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(1)
22259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(2)
22359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(3)
22459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(4)
22559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(5)
22659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(6)
22759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_in_offset(7)
22859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
22959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* Temperatures */
23059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_temp(struct device *dev, struct device_attribute *attr,
23159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
23259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
23359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
23459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
23559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
23659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
23759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
23859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
23959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
24059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
24159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
24259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
24359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
24459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
24559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
24659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
24759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
24859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
24959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
25059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
25159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
25259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
25359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
25459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
25559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
25659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
25759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
25859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		const char *buf, size_t count)
25959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
26059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
26159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
26259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct i2c_client *client = to_i2c_client(dev);
26359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = i2c_get_clientdata(client);
2647cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	long val;
2657cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	int err;
2667cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck
2677cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	err = kstrtol(buf, 10, &val);
2687cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (err)
2697cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		return err;
27059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
271e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_lock(&data->update_lock);
27259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	data->temp_min[nr] = TEMP_TO_REG(val);
27359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
27459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						data->temp_min[nr]);
275e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_unlock(&data->update_lock);
27659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return count;
27759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
27859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
27959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
28059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		const char *buf, size_t count)
28159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
28259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
28359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
28459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct i2c_client *client = to_i2c_client(dev);
28559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = i2c_get_clientdata(client);
2867cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	long val;
2877cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	int err;
2887cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck
2897cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	err = kstrtol(buf, 10, &val);
2907cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (err)
2917cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		return err;
29259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
293e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_lock(&data->update_lock);
29459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	data->temp_max[nr] = TEMP_TO_REG(val);
29559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
29659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						data->temp_max[nr]);
297e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_unlock(&data->update_lock);
29859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return count;
29959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
30059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
30159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_temp_offset(struct device *dev, struct device_attribute
30259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		*attr, char *buf)
30359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
30459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
30559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
30659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
30759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
30859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
30959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
31059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t set_temp_offset(struct device *dev, struct device_attribute
31159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		*attr, const char *buf, size_t count)
31259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
31359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
31459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
31559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct i2c_client *client = to_i2c_client(dev);
31659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = i2c_get_clientdata(client);
31759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
3187cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	long val;
3197cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	int err;
3207cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck
3217cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	err = kstrtol(buf, 10, &val);
3227cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (err)
3237cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		return err;
32459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
325e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_lock(&data->update_lock);
32659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	data->temp_offset[nr] = TEMP_TO_REG(val);
3277cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (nr > 1)
32859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		i2c_smbus_write_byte_data(client,
32959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
33059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	else if (data->temp_offset[nr] != 0) {
3317cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		/*
3327cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		 * offset[0] and offset[1] share the same register,
3337cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		 * SFR bit 4 activates offset[0]
3347cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		 */
33559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
3367cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck					(sfr & 0xef) | (nr == 0 ? 0x10 : 0));
33759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		data->temp_offset[1-nr] = 0;
33859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		i2c_smbus_write_byte_data(client,
33959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);
3407cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	} else if ((sfr & 0x10) == (nr == 0 ? 0x10 : 0))
34159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		i2c_smbus_write_byte_data(client,
34259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick					SMSC47M192_REG_TEMP_OFFSET(nr), 0);
343e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_unlock(&data->update_lock);
34459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return count;
34559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
34659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
34759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick#define show_temp_index(index)						\
34859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO,			\
34959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		show_temp, NULL, index-1);				\
35059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR,		\
35159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		show_temp_min, set_temp_min, index-1);			\
35259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR,		\
35359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		show_temp_max, set_temp_max, index-1);			\
35459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR,	\
35559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		show_temp_offset, set_temp_offset, index-1);
35659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
35759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_temp_index(1)
35859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_temp_index(2)
35959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickshow_temp_index(3)
36059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
36159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* VID */
36259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_vid(struct device *dev, struct device_attribute *attr,
36359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
36459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
36559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
36659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
36759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
36859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
36959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
37059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
37159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
37259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
37390d6619a916062cb75a176aacb318d108758b4a5Jean Delvare	struct smsc47m192_data *data = dev_get_drvdata(dev);
37459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%d\n", data->vrm);
37559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
37659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
37759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
37859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		const char *buf, size_t count)
37959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
3808f74efe81d122c071410fd74f42879ef81439fa4Jean Delvare	struct smsc47m192_data *data = dev_get_drvdata(dev);
3817cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	unsigned long val;
3827cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	int err;
3837cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck
3847cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	err = kstrtoul(buf, 10, &val);
3857cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (err)
3867cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		return err;
3877cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck
3887cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	data->vrm = val;
38959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return count;
39059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
39159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
39259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
39359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick/* Alarms */
39459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
39559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		char *buf)
39659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
39759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
39859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int nr = sensor_attr->index;
39959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = smsc47m192_update_device(dev);
40059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return sprintf(buf, "%u\n", (data->alarms & nr) ? 1 : 0);
40159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
40259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
40359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
40459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
40559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
4067817a39e65f04abe136d94a65fa26b7fe3334a1fJean Delvarestatic SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 0x4000);
4077817a39e65f04abe136d94a65fa26b7fe3334a1fJean Delvarestatic SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 0x8000);
40859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
40959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
41059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
41159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 0x0008);
41259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 0x0100);
41359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
41459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
41559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
41659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
417ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvarestatic struct attribute *smsc47m192_attributes[] = {
418ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in0_input.dev_attr.attr,
419ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in0_min.dev_attr.attr,
420ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in0_max.dev_attr.attr,
421ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in0_alarm.dev_attr.attr,
422ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in1_input.dev_attr.attr,
423ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in1_min.dev_attr.attr,
424ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in1_max.dev_attr.attr,
425ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in1_alarm.dev_attr.attr,
426ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in2_input.dev_attr.attr,
427ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in2_min.dev_attr.attr,
428ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in2_max.dev_attr.attr,
429ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in2_alarm.dev_attr.attr,
430ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in3_input.dev_attr.attr,
431ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in3_min.dev_attr.attr,
432ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in3_max.dev_attr.attr,
433ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in3_alarm.dev_attr.attr,
434ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in5_input.dev_attr.attr,
435ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in5_min.dev_attr.attr,
436ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in5_max.dev_attr.attr,
437ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in5_alarm.dev_attr.attr,
438ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in6_input.dev_attr.attr,
439ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in6_min.dev_attr.attr,
440ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in6_max.dev_attr.attr,
441ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in6_alarm.dev_attr.attr,
442ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in7_input.dev_attr.attr,
443ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in7_min.dev_attr.attr,
444ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in7_max.dev_attr.attr,
445ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in7_alarm.dev_attr.attr,
446ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare
447ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp1_input.dev_attr.attr,
448ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp1_max.dev_attr.attr,
449ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp1_min.dev_attr.attr,
450ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp1_offset.dev_attr.attr,
451ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
452ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp2_input.dev_attr.attr,
453ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp2_max.dev_attr.attr,
454ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp2_min.dev_attr.attr,
455ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp2_offset.dev_attr.attr,
456ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
4577817a39e65f04abe136d94a65fa26b7fe3334a1fJean Delvare	&sensor_dev_attr_temp2_fault.dev_attr.attr,
458ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp3_input.dev_attr.attr,
459ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp3_max.dev_attr.attr,
460ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp3_min.dev_attr.attr,
461ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp3_offset.dev_attr.attr,
462ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
4637817a39e65f04abe136d94a65fa26b7fe3334a1fJean Delvare	&sensor_dev_attr_temp3_fault.dev_attr.attr,
464ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare
465ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&dev_attr_cpu0_vid.attr,
466ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&dev_attr_vrm.attr,
467ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	NULL
468ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare};
469ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare
470ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvarestatic const struct attribute_group smsc47m192_group = {
471ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	.attrs = smsc47m192_attributes,
472ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare};
473ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare
474ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvarestatic struct attribute *smsc47m192_attributes_in4[] = {
475ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in4_input.dev_attr.attr,
476ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in4_min.dev_attr.attr,
477ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in4_max.dev_attr.attr,
478ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	&sensor_dev_attr_in4_alarm.dev_attr.attr,
479ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	NULL
480ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare};
481ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare
482ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvarestatic const struct attribute_group smsc47m192_group_in4 = {
483ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	.attrs = smsc47m192_attributes_in4,
484ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare};
485ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare
48659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic void smsc47m192_init_client(struct i2c_client *client)
48759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
48859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int i;
48959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
49059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
49159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
49259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	/* select cycle mode (pause 1 sec between updates) */
49359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,
49459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						(sfr & 0xfd) | 0x02);
49559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	if (!(config & 0x01)) {
49659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		/* initialize alarm limits */
4977cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		for (i = 0; i < 8; i++) {
49859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			i2c_smbus_write_byte_data(client,
49959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick				SMSC47M192_REG_IN_MIN(i), 0);
50059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			i2c_smbus_write_byte_data(client,
50159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick				SMSC47M192_REG_IN_MAX(i), 0xff);
50259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		}
5037cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		for (i = 0; i < 3; i++) {
50459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			i2c_smbus_write_byte_data(client,
50559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick				SMSC47M192_REG_TEMP_MIN[i], 0x80);
50659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			i2c_smbus_write_byte_data(client,
50759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick				SMSC47M192_REG_TEMP_MAX[i], 0x7f);
50859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		}
50959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
51059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		/* start monitoring */
51159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		i2c_smbus_write_byte_data(client, SMSC47M192_REG_CONFIG,
51259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						(config & 0xf7) | 0x01);
51359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	}
51459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
51559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
5168fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare/* Return 0 if detection is successful, -ENODEV otherwise */
517310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int smsc47m192_detect(struct i2c_client *client,
5188fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare			     struct i2c_board_info *info)
51959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
5208fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	struct i2c_adapter *adapter = client->adapter;
5218fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	int version;
52259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
52359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
5248fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare		return -ENODEV;
52559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
52659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	/* Detection criteria from sensors_detect script */
52752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	version = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VERSION);
52852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	if (i2c_smbus_read_byte_data(client,
52959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick				SMSC47M192_REG_COMPANY_ID) == 0x55
53052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	 && (version & 0xf0) == 0x20
53152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	 && (i2c_smbus_read_byte_data(client,
53259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick				SMSC47M192_REG_VID) & 0x70) == 0x00
53352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	 && (i2c_smbus_read_byte_data(client,
53459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick				SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
53552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare		dev_info(&adapter->dev,
53652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			 "found SMSC47M192 or compatible, "
53752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			 "version 2, stepping A%d\n", version & 0x0f);
53852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare	} else {
53952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare		dev_dbg(&adapter->dev,
54052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			"SMSC47M192 detection failed at 0x%02x\n",
54152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare			client->addr);
54252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare		return -ENODEV;
54359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	}
54459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
5458fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	strlcpy(info->type, "smsc47m192", I2C_NAME_SIZE);
5468fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare
5478fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	return 0;
5488fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare}
5498fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare
5508fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvarestatic int smsc47m192_probe(struct i2c_client *client,
5518fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare			    const struct i2c_device_id *id)
5528fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare{
5538fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	struct smsc47m192_data *data;
5548fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	int config;
5558fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	int err;
5568fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare
5578fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL);
5588fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	if (!data) {
5598fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare		err = -ENOMEM;
5608fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare		goto exit;
5618fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	}
5628fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare
5638fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare	i2c_set_clientdata(client, data);
56459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	data->vrm = vid_which_vrm();
565e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_init(&data->update_lock);
56659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
56759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	/* Initialize the SMSC47M192 chip */
56859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	smsc47m192_init_client(client);
56959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
57059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	/* Register sysfs hooks */
5717cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group);
5727cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck	if (err)
5738fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvare		goto exit_free;
57459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
57559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	/* Pin 110 is either in4 (+12V) or VID4 */
57659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
57759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	if (!(config & 0x20)) {
5787cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		err = sysfs_create_group(&client->dev.kobj,
5797cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck					 &smsc47m192_group_in4);
5807cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		if (err)
581ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare			goto exit_remove_files;
582ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	}
583ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare
5841beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	data->hwmon_dev = hwmon_device_register(&client->dev);
5851beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	if (IS_ERR(data->hwmon_dev)) {
5861beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones		err = PTR_ERR(data->hwmon_dev);
587ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare		goto exit_remove_files;
58859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	}
58959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
59059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return 0;
59159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
592ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvareexit_remove_files:
593ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
594ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
59559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickexit_free:
59659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	kfree(data);
59759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickexit:
59859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return err;
59959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
60059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
6018fb597bb6ec80d53836229bf3576c7b848b909e3Jean Delvarestatic int smsc47m192_remove(struct i2c_client *client)
60259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
60359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = i2c_get_clientdata(client);
60459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
6051beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones	hwmon_device_unregister(data->hwmon_dev);
606ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
607ce8c6ce1eceecfe090f6c1aa4108087b2051497bJean Delvare	sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
60859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
60959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	kfree(data);
61059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
61159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return 0;
61259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
61359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
61459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rickstatic struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
61559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick{
61659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct i2c_client *client = to_i2c_client(dev);
61759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	struct smsc47m192_data *data = i2c_get_clientdata(client);
61859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	int i, config;
61959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
620e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_lock(&data->update_lock);
62159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
62259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
62359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	 || !data->valid) {
62459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
62559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
62659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		dev_dbg(&client->dev, "Starting smsc47m192 update\n");
62759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
62859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		for (i = 0; i <= 7; i++) {
62959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->in[i] = i2c_smbus_read_byte_data(client,
63059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_IN(i));
63159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->in_min[i] = i2c_smbus_read_byte_data(client,
63259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_IN_MIN(i));
63359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->in_max[i] = i2c_smbus_read_byte_data(client,
63459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_IN_MAX(i));
63559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		}
63659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		for (i = 0; i < 3; i++) {
63759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->temp[i] = i2c_smbus_read_byte_data(client,
63859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_TEMP[i]);
63959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->temp_max[i] = i2c_smbus_read_byte_data(client,
64059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_TEMP_MAX[i]);
64159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->temp_min[i] = i2c_smbus_read_byte_data(client,
64259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_TEMP_MIN[i]);
64359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		}
64459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		for (i = 1; i < 3; i++)
64559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->temp_offset[i] = i2c_smbus_read_byte_data(client,
64659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_TEMP_OFFSET(i));
6477cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		/*
6487cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		 * first offset is temp_offset[0] if SFR bit 4 is set,
6497cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		 * temp_offset[1] otherwise
6507cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck		 */
65159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		if (sfr & 0x10) {
65259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->temp_offset[0] = data->temp_offset[1];
65359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->temp_offset[1] = 0;
65459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		} else
65559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->temp_offset[0] = 0;
65659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
65759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID)
65859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			    & 0x0f;
65959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		config = i2c_smbus_read_byte_data(client,
66059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						  SMSC47M192_REG_CONFIG);
66159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		if (config & 0x20)
66259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			data->vid |= (i2c_smbus_read_byte_data(client,
66359ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick					SMSC47M192_REG_VID4) & 0x01) << 4;
66459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		data->alarms = i2c_smbus_read_byte_data(client,
66559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick						SMSC47M192_REG_ALARM1) |
66659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick			       (i2c_smbus_read_byte_data(client,
6677cc3cb6662a21a59a2e0e752a8ebd95137c71d3aGuenter Roeck						SMSC47M192_REG_ALARM2) << 8);
66859ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
66959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		data->last_updated = jiffies;
67059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick		data->valid = 1;
67159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	}
67259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
673e4a7167f82130fa95005097797bb1ec9c76201fdJean Delvare	mutex_unlock(&data->update_lock);
67459ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
67559ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick	return data;
67659ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick}
67759ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
678f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(smsc47m192_driver);
67959ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut Rick
68059ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut RickMODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>");
68159ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut RickMODULE_DESCRIPTION("SMSC47M192 driver");
68259ac83677f72ea2cc25b5426e7df9589aa7a5384Hartmut RickMODULE_LICENSE("GPL");
683