Blame view

drivers/macintosh/windfarm_smu_sat.c 8.2 KB
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Windfarm PowerMac thermal control.  SMU "satellite" controller sensors.
   *
   * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org>
   *
   * Released under the terms of the GNU GPL v2.
   */
  
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/init.h>
  #include <linux/wait.h>
  #include <linux/i2c.h>
56783c5e4   Daniel Walker   [POWERPC] macinto...
16
  #include <linux/mutex.h>
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
17
18
19
20
21
  #include <asm/prom.h>
  #include <asm/smu.h>
  #include <asm/pmac_low_i2c.h>
  
  #include "windfarm.h"
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
22
  #define VERSION "1.0"
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
23
24
25
26
27
28
29
30
31
32
33
34
35
  
  #define DEBUG
  
  #ifdef DEBUG
  #define DBG(args...)	printk(args)
  #else
  #define DBG(args...)	do { } while(0)
  #endif
  
  /* If the cache is older than 800ms we'll refetch it */
  #define MAX_AGE		msecs_to_jiffies(800)
  
  struct wf_sat {
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
36
  	struct kref		ref;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
37
  	int			nr;
56783c5e4   Daniel Walker   [POWERPC] macinto...
38
  	struct mutex		mutex;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
39
40
  	unsigned long		last_read; /* jiffies when cache last updated */
  	u8			cache[16];
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
41
  	struct list_head	sensors;
351ca3e31   Jean Delvare   windfarm: Convert...
42
  	struct i2c_client	*i2c;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
43
44
45
46
47
48
  	struct device_node	*node;
  };
  
  static struct wf_sat *sats[2];
  
  struct wf_sat_sensor {
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
49
50
51
52
53
54
  	struct list_head	link;
  	int			index;
  	int			index2;		/* used for power sensors */
  	int			shift;
  	struct wf_sat		*sat;
  	struct wf_sensor 	sens;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
55
56
57
  };
  
  #define wf_to_sat(c)	container_of(c, struct wf_sat_sensor, sens)
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
58

ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
59
60
61
62
63
64
65
66
67
68
69
70
71
  struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
  						  unsigned int *size)
  {
  	struct wf_sat *sat;
  	int err;
  	unsigned int i, len;
  	u8 *buf;
  	u8 data[4];
  
  	/* TODO: Add the resulting partition to the device-tree */
  
  	if (sat_id > 1 || (sat = sats[sat_id]) == NULL)
  		return NULL;
351ca3e31   Jean Delvare   windfarm: Convert...
72
  	err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
73
74
75
76
77
  	if (err) {
  		printk(KERN_ERR "smu_sat_get_sdb_part wr error %d
  ", err);
  		return NULL;
  	}
351ca3e31   Jean Delvare   windfarm: Convert...
78
  	err = i2c_smbus_read_word_data(sat->i2c, 9);
2fd091f3e   roel kluin   powerpc/macintosh...
79
  	if (err < 0) {
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
80
81
82
83
  		printk(KERN_ERR "smu_sat_get_sdb_part rd len error
  ");
  		return NULL;
  	}
2fd091f3e   roel kluin   powerpc/macintosh...
84
  	len = err;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
85
86
87
88
89
90
91
92
93
94
95
96
97
  	if (len == 0) {
  		printk(KERN_ERR "smu_sat_get_sdb_part no partition %x
  ", id);
  		return NULL;
  	}
  
  	len = le16_to_cpu(len);
  	len = (len + 3) & ~3;
  	buf = kmalloc(len, GFP_KERNEL);
  	if (buf == NULL)
  		return NULL;
  
  	for (i = 0; i < len; i += 4) {
351ca3e31   Jean Delvare   windfarm: Convert...
98
  		err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data);
4b2643d7d   Jean Delvare   i2c: Fix the i2c_...
99
  		if (err < 0) {
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  			printk(KERN_ERR "smu_sat_get_sdb_part rd err %d
  ",
  			       err);
  			goto fail;
  		}
  		buf[i] = data[1];
  		buf[i+1] = data[0];
  		buf[i+2] = data[3];
  		buf[i+3] = data[2];
  	}
  #ifdef DEBUG
  	DBG(KERN_DEBUG "sat %d partition %x:", sat_id, id);
  	for (i = 0; i < len; ++i)
  		DBG(" %x", buf[i]);
  	DBG("
  ");
  #endif
  
  	if (size)
  		*size = len;
  	return (struct smu_sdbp_header *) buf;
  
   fail:
  	kfree(buf);
  	return NULL;
  }
9127dd1aa   Johannes Berg   [PATCH] allow win...
126
  EXPORT_SYMBOL_GPL(smu_sat_get_sdb_partition);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
127
128
129
130
131
  
  /* refresh the cache */
  static int wf_sat_read_cache(struct wf_sat *sat)
  {
  	int err;
351ca3e31   Jean Delvare   windfarm: Convert...
132
  	err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache);
4b2643d7d   Jean Delvare   i2c: Fix the i2c_...
133
  	if (err < 0)
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  		return err;
  	sat->last_read = jiffies;
  #ifdef LOTSA_DEBUG
  	{
  		int i;
  		DBG(KERN_DEBUG "wf_sat_get: data is");
  		for (i = 0; i < 16; ++i)
  			DBG(" %.2x", sat->cache[i]);
  		DBG("
  ");
  	}
  #endif
  	return 0;
  }
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
148
  static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value)
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
149
150
151
152
153
  {
  	struct wf_sat_sensor *sens = wf_to_sat(sr);
  	struct wf_sat *sat = sens->sat;
  	int i, err;
  	s32 val;
351ca3e31   Jean Delvare   windfarm: Convert...
154
  	if (sat->i2c == NULL)
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
155
  		return -ENODEV;
56783c5e4   Daniel Walker   [POWERPC] macinto...
156
  	mutex_lock(&sat->mutex);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  	if (time_after(jiffies, (sat->last_read + MAX_AGE))) {
  		err = wf_sat_read_cache(sat);
  		if (err)
  			goto fail;
  	}
  
  	i = sens->index * 2;
  	val = ((sat->cache[i] << 8) + sat->cache[i+1]) << sens->shift;
  	if (sens->index2 >= 0) {
  		i = sens->index2 * 2;
  		/* 4.12 * 8.8 -> 12.20; shift right 4 to get 16.16 */
  		val = (val * ((sat->cache[i] << 8) + sat->cache[i+1])) >> 4;
  	}
  
  	*value = val;
  	err = 0;
  
   fail:
56783c5e4   Daniel Walker   [POWERPC] macinto...
175
  	mutex_unlock(&sat->mutex);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
176
177
  	return err;
  }
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
178
179
180
181
182
183
184
185
186
187
  static void wf_sat_release(struct kref *ref)
  {
  	struct wf_sat *sat = container_of(ref, struct wf_sat, ref);
  
  	if (sat->nr >= 0)
  		sats[sat->nr] = NULL;
  	kfree(sat);
  }
  
  static void wf_sat_sensor_release(struct wf_sensor *sr)
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
188
189
190
  {
  	struct wf_sat_sensor *sens = wf_to_sat(sr);
  	struct wf_sat *sat = sens->sat;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
191
  	kfree(sens);
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
192
  	kref_put(&sat->ref, wf_sat_release);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
193
194
195
  }
  
  static struct wf_sensor_ops wf_sat_ops = {
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
196
197
  	.get_value	= wf_sat_sensor_get,
  	.release	= wf_sat_sensor_release,
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
198
199
  	.owner		= THIS_MODULE,
  };
351ca3e31   Jean Delvare   windfarm: Convert...
200
201
202
  static int wf_sat_probe(struct i2c_client *client,
  			const struct i2c_device_id *id)
  {
9525a08b3   Benjamin Herrenschmidt   powerpc/windfarm:...
203
  	struct device_node *dev = client->dev.of_node;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
204
205
  	struct wf_sat *sat;
  	struct wf_sat_sensor *sens;
018a3d1db   Jeremy Kerr   [POWERPC] powerma...
206
207
  	const u32 *reg;
  	const char *loc, *type;
351ca3e31   Jean Delvare   windfarm: Convert...
208
  	u8 chip, core;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
209
210
211
212
  	struct device_node *child;
  	int shift, cpu, index;
  	char *name;
  	int vsens[2], isens[2];
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
213
214
  	sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL);
  	if (sat == NULL)
351ca3e31   Jean Delvare   windfarm: Convert...
215
  		return -ENOMEM;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
216
217
  	sat->nr = -1;
  	sat->node = of_node_get(dev);
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
218
  	kref_init(&sat->ref);
56783c5e4   Daniel Walker   [POWERPC] macinto...
219
  	mutex_init(&sat->mutex);
351ca3e31   Jean Delvare   windfarm: Convert...
220
  	sat->i2c = client;
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
221
  	INIT_LIST_HEAD(&sat->sensors);
351ca3e31   Jean Delvare   windfarm: Convert...
222
  	i2c_set_clientdata(client, sat);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
223
224
225
226
227
  
  	vsens[0] = vsens[1] = -1;
  	isens[0] = isens[1] = -1;
  	child = NULL;
  	while ((child = of_get_next_child(dev, child)) != NULL) {
01b2726dd   Stephen Rothwell   [POWERPC] Rename ...
228
229
230
  		reg = of_get_property(child, "reg", NULL);
  		type = of_get_property(child, "device_type", NULL);
  		loc = of_get_property(child, "location", NULL);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  		if (reg == NULL || loc == NULL)
  			continue;
  
  		/* the cooked sensors are between 0x30 and 0x37 */
  		if (*reg < 0x30 || *reg > 0x37)
  			continue;
  		index = *reg - 0x30;
  
  		/* expect location to be CPU [AB][01] ... */
  		if (strncmp(loc, "CPU ", 4) != 0)
  			continue;
  		chip = loc[4] - 'A';
  		core = loc[5] - '0';
  		if (chip > 1 || core > 1) {
  			printk(KERN_ERR "wf_sat_create: don't understand "
  			       "location %s for %s
  ", loc, child->full_name);
  			continue;
  		}
  		cpu = 2 * chip + core;
  		if (sat->nr < 0)
  			sat->nr = chip;
  		else if (sat->nr != chip) {
  			printk(KERN_ERR "wf_sat_create: can't cope with "
  			       "multiple CPU chips on one SAT (%s)
  ", loc);
  			continue;
  		}
  
  		if (strcmp(type, "voltage-sensor") == 0) {
  			name = "cpu-voltage";
  			shift = 4;
  			vsens[core] = index;
  		} else if (strcmp(type, "current-sensor") == 0) {
  			name = "cpu-current";
  			shift = 8;
  			isens[core] = index;
  		} else if (strcmp(type, "temp-sensor") == 0) {
  			name = "cpu-temp";
  			shift = 10;
  		} else
  			continue;	/* hmmm shouldn't happen */
  
  		/* the +16 is enough for "cpu-voltage-n" */
  		sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL);
  		if (sens == NULL) {
  			printk(KERN_ERR "wf_sat_create: couldn't create "
  			       "%s sensor %d (no memory)
  ", name, cpu);
  			continue;
  		}
  		sens->index = index;
  		sens->index2 = -1;
  		sens->shift = shift;
  		sens->sat = sat;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
286
287
  		sens->sens.ops = &wf_sat_ops;
  		sens->sens.name = (char *) (sens + 1);
43671cc96   Stephen Rothwell   powerpc/windfarm:...
288
  		snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
289

e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
290
  		if (wf_register_sensor(&sens->sens))
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
291
  			kfree(sens);
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
292
293
294
  		else {
  			list_add(&sens->link, &sat->sensors);
  			kref_get(&sat->ref);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  		}
  	}
  
  	/* make the power sensors */
  	for (core = 0; core < 2; ++core) {
  		if (vsens[core] < 0 || isens[core] < 0)
  			continue;
  		cpu = 2 * sat->nr + core;
  		sens = kzalloc(sizeof(struct wf_sat_sensor) + 16, GFP_KERNEL);
  		if (sens == NULL) {
  			printk(KERN_ERR "wf_sat_create: couldn't create power "
  			       "sensor %d (no memory)
  ", cpu);
  			continue;
  		}
  		sens->index = vsens[core];
  		sens->index2 = isens[core];
  		sens->shift = 0;
  		sens->sat = sat;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
314
315
  		sens->sens.ops = &wf_sat_ops;
  		sens->sens.name = (char *) (sens + 1);
43671cc96   Stephen Rothwell   powerpc/windfarm:...
316
  		snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
317

e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
318
  		if (wf_register_sensor(&sens->sens))
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
319
  			kfree(sens);
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
320
321
322
  		else {
  			list_add(&sens->link, &sat->sensors);
  			kref_get(&sat->ref);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
323
324
325
326
327
  		}
  	}
  
  	if (sat->nr >= 0)
  		sats[sat->nr] = sat;
351ca3e31   Jean Delvare   windfarm: Convert...
328
  	return 0;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
329
  }
351ca3e31   Jean Delvare   windfarm: Convert...
330
  static int wf_sat_remove(struct i2c_client *client)
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
331
  {
351ca3e31   Jean Delvare   windfarm: Convert...
332
  	struct wf_sat *sat = i2c_get_clientdata(client);
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
333
  	struct wf_sat_sensor *sens;
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
334

e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
335
336
337
338
339
340
341
  	/* release sensors */
  	while(!list_empty(&sat->sensors)) {
  		sens = list_first_entry(&sat->sensors,
  					struct wf_sat_sensor, link);
  		list_del(&sens->link);
  		wf_unregister_sensor(&sens->sens);
  	}
351ca3e31   Jean Delvare   windfarm: Convert...
342
  	sat->i2c = NULL;
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
343
  	kref_put(&sat->ref, wf_sat_release);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
344
345
  	return 0;
  }
351ca3e31   Jean Delvare   windfarm: Convert...
346
  static const struct i2c_device_id wf_sat_id[] = {
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
347
  	{ "MAC,smu-sat", 0 },
351ca3e31   Jean Delvare   windfarm: Convert...
348
349
  	{ }
  };
e326b30fd   Benjamin Herrenschmidt   powerpc/pmac: Con...
350
  MODULE_DEVICE_TABLE(i2c, wf_sat_id);
351ca3e31   Jean Delvare   windfarm: Convert...
351
352
353
354
355
  
  static struct i2c_driver wf_sat_driver = {
  	.driver = {
  		.name		= "wf_smu_sat",
  	},
351ca3e31   Jean Delvare   windfarm: Convert...
356
357
358
359
  	.probe		= wf_sat_probe,
  	.remove		= wf_sat_remove,
  	.id_table	= wf_sat_id,
  };
f7fb862b8   Wei Yongjun   powerpc/windfarm:...
360
  module_i2c_driver(wf_sat_driver);
ac171c466   Benjamin Herrenschmidt   [PATCH] powerpc: ...
361
362
363
364
  
  MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
  MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
  MODULE_LICENSE("GPL");