Blame view

drivers/hwmon/ds620.c 6.58 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
609946980   Roland Stigge   hwmon: Support fo...
2
3
4
5
6
7
  /*
   *  ds620.c - Support for temperature sensor and thermostat DS620
   *
   *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
   *
   *  based on ds1621.c by Christian W. Zuckschwerdt  <zany@triq.net>
609946980   Roland Stigge   hwmon: Support fo...
8
9
10
11
12
13
14
15
16
17
18
19
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/jiffies.h>
  #include <linux/i2c.h>
  #include <linux/hwmon.h>
  #include <linux/hwmon-sysfs.h>
  #include <linux/err.h>
  #include <linux/mutex.h>
  #include <linux/sysfs.h>
570999f30   Wolfram Sang   hwmon: (ds620) mo...
20
  #include <linux/platform_data/ds620.h>
609946980   Roland Stigge   hwmon: Support fo...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  
  /*
   * Many DS620 constants specified below
   *  15   14   13   12   11   10   09    08
   * |Done|NVB |THF |TLF |R1  |R0  |AUTOC|1SHOT|
   *
   *  07   06   05   04   03   02   01    00
   * |PO2 |PO1 |A2  |A1  |A0  |    |     |     |
   */
  #define DS620_REG_CONFIG_DONE		0x8000
  #define DS620_REG_CONFIG_NVB		0x4000
  #define DS620_REG_CONFIG_THF		0x2000
  #define DS620_REG_CONFIG_TLF		0x1000
  #define DS620_REG_CONFIG_R1		0x0800
  #define DS620_REG_CONFIG_R0		0x0400
  #define DS620_REG_CONFIG_AUTOC		0x0200
  #define DS620_REG_CONFIG_1SHOT		0x0100
  #define DS620_REG_CONFIG_PO2		0x0080
  #define DS620_REG_CONFIG_PO1		0x0040
  #define DS620_REG_CONFIG_A2		0x0020
  #define DS620_REG_CONFIG_A1		0x0010
  #define DS620_REG_CONFIG_A0		0x0008
  
  /* The DS620 registers */
  static const u8 DS620_REG_TEMP[3] = {
  	0xAA,			/* input, word, RO */
  	0xA2,			/* min, word, RW */
  	0xA0,			/* max, word, RW */
  };
  
  #define DS620_REG_CONF		0xAC	/* word, RW */
  #define DS620_COM_START		0x51	/* no data */
  #define DS620_COM_STOP		0x22	/* no data */
  
  /* Each client has this additional data */
  struct ds620_data {
f073b9942   Axel Lin   hwmon: (ds620) Co...
57
  	struct i2c_client *client;
609946980   Roland Stigge   hwmon: Support fo...
58
59
60
  	struct mutex update_lock;
  	char valid;		/* !=0 if following fields are valid */
  	unsigned long last_updated;	/* In jiffies */
cc41d586e   Roland Stigge   hwmon: (ds620) Fi...
61
  	s16 temp[3];		/* Register values, word */
609946980   Roland Stigge   hwmon: Support fo...
62
  };
609946980   Roland Stigge   hwmon: Support fo...
63
64
  static void ds620_init_client(struct i2c_client *client)
  {
a8b3a3a53   Jingoo Han   hwmon: use dev_ge...
65
  	struct ds620_platform_data *ds620_info = dev_get_platdata(&client->dev);
609946980   Roland Stigge   hwmon: Support fo...
66
67
68
  	u16 conf, new_conf;
  
  	new_conf = conf =
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
69
  	    i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
609946980   Roland Stigge   hwmon: Support fo...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  
  	/* switch to continuous conversion mode */
  	new_conf &= ~DS620_REG_CONFIG_1SHOT;
  	/* already high at power-on, but don't trust the BIOS! */
  	new_conf |= DS620_REG_CONFIG_PO2;
  	/* thermostat mode according to platform data */
  	if (ds620_info && ds620_info->pomode == 1)
  		new_conf &= ~DS620_REG_CONFIG_PO1; /* PO_LOW */
  	else if (ds620_info && ds620_info->pomode == 2)
  		new_conf |= DS620_REG_CONFIG_PO1; /* PO_HIGH */
  	else
  		new_conf &= ~DS620_REG_CONFIG_PO2; /* always low */
  	/* with highest precision */
  	new_conf |= DS620_REG_CONFIG_R1 | DS620_REG_CONFIG_R0;
  
  	if (conf != new_conf)
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
86
  		i2c_smbus_write_word_swapped(client, DS620_REG_CONF, new_conf);
609946980   Roland Stigge   hwmon: Support fo...
87
88
89
90
91
92
93
  
  	/* start conversion */
  	i2c_smbus_write_byte(client, DS620_COM_START);
  }
  
  static struct ds620_data *ds620_update_client(struct device *dev)
  {
f073b9942   Axel Lin   hwmon: (ds620) Co...
94
95
  	struct ds620_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
609946980   Roland Stigge   hwmon: Support fo...
96
97
98
99
100
101
102
103
104
105
106
107
108
  	struct ds620_data *ret = data;
  
  	mutex_lock(&data->update_lock);
  
  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
  	    || !data->valid) {
  		int i;
  		int res;
  
  		dev_dbg(&client->dev, "Starting ds620 update
  ");
  
  		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
109
110
  			res = i2c_smbus_read_word_swapped(client,
  							  DS620_REG_TEMP[i]);
609946980   Roland Stigge   hwmon: Support fo...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  			if (res < 0) {
  				ret = ERR_PTR(res);
  				goto abort;
  			}
  
  			data->temp[i] = res;
  		}
  
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
  abort:
  	mutex_unlock(&data->update_lock);
  
  	return ret;
  }
57549f336   Guenter Roeck   hwmon: (ds620) Us...
127
  static ssize_t temp_show(struct device *dev, struct device_attribute *da,
609946980   Roland Stigge   hwmon: Support fo...
128
129
130
131
132
133
134
135
136
137
138
  			 char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	struct ds620_data *data = ds620_update_client(dev);
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
  
  	return sprintf(buf, "%d
  ", ((data->temp[attr->index] / 8) * 625) / 10);
  }
57549f336   Guenter Roeck   hwmon: (ds620) Us...
139
140
  static ssize_t temp_store(struct device *dev, struct device_attribute *da,
  			  const char *buf, size_t count)
609946980   Roland Stigge   hwmon: Support fo...
141
142
143
144
145
  {
  	int res;
  	long val;
  
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
f073b9942   Axel Lin   hwmon: (ds620) Co...
146
147
  	struct ds620_data *data = dev_get_drvdata(dev);
  	struct i2c_client *client = data->client;
609946980   Roland Stigge   hwmon: Support fo...
148

179c4fdb5   Frans Meulenbroeks   hwmon: replaced s...
149
  	res = kstrtol(buf, 10, &val);
609946980   Roland Stigge   hwmon: Support fo...
150
151
152
  
  	if (res)
  		return res;
e36ce99ee   Guenter Roeck   hwmon: (ds620) Fi...
153
  	val = (clamp_val(val, -128000, 128000) * 10 / 625) * 8;
609946980   Roland Stigge   hwmon: Support fo...
154
155
156
  
  	mutex_lock(&data->update_lock);
  	data->temp[attr->index] = val;
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
157
158
  	i2c_smbus_write_word_swapped(client, DS620_REG_TEMP[attr->index],
  				     data->temp[attr->index]);
609946980   Roland Stigge   hwmon: Support fo...
159
160
161
  	mutex_unlock(&data->update_lock);
  	return count;
  }
57549f336   Guenter Roeck   hwmon: (ds620) Us...
162
  static ssize_t alarm_show(struct device *dev, struct device_attribute *da,
609946980   Roland Stigge   hwmon: Support fo...
163
164
165
166
  			  char *buf)
  {
  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  	struct ds620_data *data = ds620_update_client(dev);
f073b9942   Axel Lin   hwmon: (ds620) Co...
167
  	struct i2c_client *client;
609946980   Roland Stigge   hwmon: Support fo...
168
169
170
171
172
  	u16 conf, new_conf;
  	int res;
  
  	if (IS_ERR(data))
  		return PTR_ERR(data);
f073b9942   Axel Lin   hwmon: (ds620) Co...
173
  	client = data->client;
609946980   Roland Stigge   hwmon: Support fo...
174
  	/* reset alarms if necessary */
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
175
  	res = i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
609946980   Roland Stigge   hwmon: Support fo...
176
177
  	if (res < 0)
  		return res;
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
178
  	new_conf = conf = res;
609946980   Roland Stigge   hwmon: Support fo...
179
180
  	new_conf &= ~attr->index;
  	if (conf != new_conf) {
90f4102ce   Jean Delvare   hwmon: Use i2c_sm...
181
182
  		res = i2c_smbus_write_word_swapped(client, DS620_REG_CONF,
  						   new_conf);
609946980   Roland Stigge   hwmon: Support fo...
183
184
185
186
187
188
189
  		if (res < 0)
  			return res;
  	}
  
  	return sprintf(buf, "%d
  ", !!(conf & attr->index));
  }
57549f336   Guenter Roeck   hwmon: (ds620) Us...
190
191
192
193
194
  static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
  static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, 1);
  static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, 2);
  static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, DS620_REG_CONFIG_TLF);
  static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, DS620_REG_CONFIG_THF);
609946980   Roland Stigge   hwmon: Support fo...
195

f073b9942   Axel Lin   hwmon: (ds620) Co...
196
  static struct attribute *ds620_attrs[] = {
609946980   Roland Stigge   hwmon: Support fo...
197
198
199
200
201
202
203
  	&sensor_dev_attr_temp1_input.dev_attr.attr,
  	&sensor_dev_attr_temp1_min.dev_attr.attr,
  	&sensor_dev_attr_temp1_max.dev_attr.attr,
  	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
  	NULL
  };
f073b9942   Axel Lin   hwmon: (ds620) Co...
204
  ATTRIBUTE_GROUPS(ds620);
609946980   Roland Stigge   hwmon: Support fo...
205

674870385   Stephen Kitt   hwmon: use simple...
206
  static int ds620_probe(struct i2c_client *client)
609946980   Roland Stigge   hwmon: Support fo...
207
  {
f073b9942   Axel Lin   hwmon: (ds620) Co...
208
209
  	struct device *dev = &client->dev;
  	struct device *hwmon_dev;
609946980   Roland Stigge   hwmon: Support fo...
210
  	struct ds620_data *data;
609946980   Roland Stigge   hwmon: Support fo...
211

f073b9942   Axel Lin   hwmon: (ds620) Co...
212
  	data = devm_kzalloc(dev, sizeof(struct ds620_data), GFP_KERNEL);
3aa9d1df7   Guenter Roeck   hwmon: (ds620) Co...
213
214
  	if (!data)
  		return -ENOMEM;
609946980   Roland Stigge   hwmon: Support fo...
215

f073b9942   Axel Lin   hwmon: (ds620) Co...
216
  	data->client = client;
609946980   Roland Stigge   hwmon: Support fo...
217
218
219
220
  	mutex_init(&data->update_lock);
  
  	/* Initialize the DS620 chip */
  	ds620_init_client(client);
f073b9942   Axel Lin   hwmon: (ds620) Co...
221
222
223
  	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
  							   data, ds620_groups);
  	return PTR_ERR_OR_ZERO(hwmon_dev);
609946980   Roland Stigge   hwmon: Support fo...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  }
  
  static const struct i2c_device_id ds620_id[] = {
  	{"ds620", 0},
  	{}
  };
  
  MODULE_DEVICE_TABLE(i2c, ds620_id);
  
  /* This is the driver that will be inserted */
  static struct i2c_driver ds620_driver = {
  	.class = I2C_CLASS_HWMON,
  	.driver = {
  		   .name = "ds620",
  	},
674870385   Stephen Kitt   hwmon: use simple...
239
  	.probe_new = ds620_probe,
609946980   Roland Stigge   hwmon: Support fo...
240
241
  	.id_table = ds620_id,
  };
f0967eea8   Axel Lin   hwmon: convert dr...
242
  module_i2c_driver(ds620_driver);
609946980   Roland Stigge   hwmon: Support fo...
243
244
245
246
  
  MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
  MODULE_DESCRIPTION("DS620 driver");
  MODULE_LICENSE("GPL");