diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-04-18 18:16:46 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-04-30 01:37:19 -0400 |
commit | e326b30fda9a985a2e7fda6fb9212b86bf025c39 (patch) | |
tree | a72930b7ffe88e558d3fd4fdb00db2ccf9169adb /drivers/macintosh | |
parent | 22b6d2ea355449fc2a9a4dc5c346615af86b876e (diff) |
powerpc/pmac: Convert windfarm_smu_sat to new i2c probing
This simplifies the driver to stop using the deprecated attach interface.
While at it we also implement teardown properly and fix the refcounting
by using a kref.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/macintosh')
-rw-r--r-- | drivers/macintosh/windfarm_smu_sat.c | 126 |
1 files changed, 47 insertions, 79 deletions
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 65a8ff3e1f8e..72dfe191235b 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | #include "windfarm.h" | 21 | #include "windfarm.h" |
22 | 22 | ||
23 | #define VERSION "0.2" | 23 | #define VERSION "1.0" |
24 | 24 | ||
25 | #define DEBUG | 25 | #define DEBUG |
26 | 26 | ||
@@ -34,11 +34,12 @@ | |||
34 | #define MAX_AGE msecs_to_jiffies(800) | 34 | #define MAX_AGE msecs_to_jiffies(800) |
35 | 35 | ||
36 | struct wf_sat { | 36 | struct wf_sat { |
37 | struct kref ref; | ||
37 | int nr; | 38 | int nr; |
38 | atomic_t refcnt; | ||
39 | struct mutex mutex; | 39 | struct mutex mutex; |
40 | unsigned long last_read; /* jiffies when cache last updated */ | 40 | unsigned long last_read; /* jiffies when cache last updated */ |
41 | u8 cache[16]; | 41 | u8 cache[16]; |
42 | struct list_head sensors; | ||
42 | struct i2c_client *i2c; | 43 | struct i2c_client *i2c; |
43 | struct device_node *node; | 44 | struct device_node *node; |
44 | }; | 45 | }; |
@@ -46,11 +47,12 @@ struct wf_sat { | |||
46 | static struct wf_sat *sats[2]; | 47 | static struct wf_sat *sats[2]; |
47 | 48 | ||
48 | struct wf_sat_sensor { | 49 | struct wf_sat_sensor { |
49 | int index; | 50 | struct list_head link; |
50 | int index2; /* used for power sensors */ | 51 | int index; |
51 | int shift; | 52 | int index2; /* used for power sensors */ |
52 | struct wf_sat *sat; | 53 | int shift; |
53 | struct wf_sensor sens; | 54 | struct wf_sat *sat; |
55 | struct wf_sensor sens; | ||
54 | }; | 56 | }; |
55 | 57 | ||
56 | #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) | 58 | #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) |
@@ -142,7 +144,7 @@ static int wf_sat_read_cache(struct wf_sat *sat) | |||
142 | return 0; | 144 | return 0; |
143 | } | 145 | } |
144 | 146 | ||
145 | static int wf_sat_get(struct wf_sensor *sr, s32 *value) | 147 | static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value) |
146 | { | 148 | { |
147 | struct wf_sat_sensor *sens = wf_to_sat(sr); | 149 | struct wf_sat_sensor *sens = wf_to_sat(sr); |
148 | struct wf_sat *sat = sens->sat; | 150 | struct wf_sat *sat = sens->sat; |
@@ -175,58 +177,30 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value) | |||
175 | return err; | 177 | return err; |
176 | } | 178 | } |
177 | 179 | ||
178 | static void wf_sat_release(struct wf_sensor *sr) | 180 | static void wf_sat_release(struct kref *ref) |
181 | { | ||
182 | struct wf_sat *sat = container_of(ref, struct wf_sat, ref); | ||
183 | |||
184 | if (sat->nr >= 0) | ||
185 | sats[sat->nr] = NULL; | ||
186 | kfree(sat); | ||
187 | } | ||
188 | |||
189 | static void wf_sat_sensor_release(struct wf_sensor *sr) | ||
179 | { | 190 | { |
180 | struct wf_sat_sensor *sens = wf_to_sat(sr); | 191 | struct wf_sat_sensor *sens = wf_to_sat(sr); |
181 | struct wf_sat *sat = sens->sat; | 192 | struct wf_sat *sat = sens->sat; |
182 | 193 | ||
183 | if (atomic_dec_and_test(&sat->refcnt)) { | ||
184 | if (sat->nr >= 0) | ||
185 | sats[sat->nr] = NULL; | ||
186 | kfree(sat); | ||
187 | } | ||
188 | kfree(sens); | 194 | kfree(sens); |
195 | kref_put(&sat->ref, wf_sat_release); | ||
189 | } | 196 | } |
190 | 197 | ||
191 | static struct wf_sensor_ops wf_sat_ops = { | 198 | static struct wf_sensor_ops wf_sat_ops = { |
192 | .get_value = wf_sat_get, | 199 | .get_value = wf_sat_sensor_get, |
193 | .release = wf_sat_release, | 200 | .release = wf_sat_sensor_release, |
194 | .owner = THIS_MODULE, | 201 | .owner = THIS_MODULE, |
195 | }; | 202 | }; |
196 | 203 | ||
197 | static struct i2c_driver wf_sat_driver; | ||
198 | |||
199 | static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) | ||
200 | { | ||
201 | struct i2c_board_info info; | ||
202 | struct i2c_client *client; | ||
203 | const u32 *reg; | ||
204 | u8 addr; | ||
205 | |||
206 | reg = of_get_property(dev, "reg", NULL); | ||
207 | if (reg == NULL) | ||
208 | return; | ||
209 | addr = *reg; | ||
210 | DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); | ||
211 | |||
212 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
213 | info.addr = (addr >> 1) & 0x7f; | ||
214 | info.platform_data = dev; | ||
215 | strlcpy(info.type, "wf_sat", I2C_NAME_SIZE); | ||
216 | |||
217 | client = i2c_new_device(adapter, &info); | ||
218 | if (client == NULL) { | ||
219 | printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Let i2c-core delete that device on driver removal. | ||
225 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
226 | */ | ||
227 | list_add_tail(&client->detected, &wf_sat_driver.clients); | ||
228 | } | ||
229 | |||
230 | static int wf_sat_probe(struct i2c_client *client, | 204 | static int wf_sat_probe(struct i2c_client *client, |
231 | const struct i2c_device_id *id) | 205 | const struct i2c_device_id *id) |
232 | { | 206 | { |
@@ -246,9 +220,10 @@ static int wf_sat_probe(struct i2c_client *client, | |||
246 | return -ENOMEM; | 220 | return -ENOMEM; |
247 | sat->nr = -1; | 221 | sat->nr = -1; |
248 | sat->node = of_node_get(dev); | 222 | sat->node = of_node_get(dev); |
249 | atomic_set(&sat->refcnt, 0); | 223 | kref_init(&sat->ref); |
250 | mutex_init(&sat->mutex); | 224 | mutex_init(&sat->mutex); |
251 | sat->i2c = client; | 225 | sat->i2c = client; |
226 | INIT_LIST_HEAD(&sat->sensors); | ||
252 | i2c_set_clientdata(client, sat); | 227 | i2c_set_clientdata(client, sat); |
253 | 228 | ||
254 | vsens[0] = vsens[1] = -1; | 229 | vsens[0] = vsens[1] = -1; |
@@ -310,14 +285,15 @@ static int wf_sat_probe(struct i2c_client *client, | |||
310 | sens->index2 = -1; | 285 | sens->index2 = -1; |
311 | sens->shift = shift; | 286 | sens->shift = shift; |
312 | sens->sat = sat; | 287 | sens->sat = sat; |
313 | atomic_inc(&sat->refcnt); | ||
314 | sens->sens.ops = &wf_sat_ops; | 288 | sens->sens.ops = &wf_sat_ops; |
315 | sens->sens.name = (char *) (sens + 1); | 289 | sens->sens.name = (char *) (sens + 1); |
316 | snprintf(sens->sens.name, 16, "%s-%d", name, cpu); | 290 | snprintf(sens->sens.name, 16, "%s-%d", name, cpu); |
317 | 291 | ||
318 | if (wf_register_sensor(&sens->sens)) { | 292 | if (wf_register_sensor(&sens->sens)) |
319 | atomic_dec(&sat->refcnt); | ||
320 | kfree(sens); | 293 | kfree(sens); |
294 | else { | ||
295 | list_add(&sens->link, &sat->sensors); | ||
296 | kref_get(&sat->ref); | ||
321 | } | 297 | } |
322 | } | 298 | } |
323 | 299 | ||
@@ -336,14 +312,15 @@ static int wf_sat_probe(struct i2c_client *client, | |||
336 | sens->index2 = isens[core]; | 312 | sens->index2 = isens[core]; |
337 | sens->shift = 0; | 313 | sens->shift = 0; |
338 | sens->sat = sat; | 314 | sens->sat = sat; |
339 | atomic_inc(&sat->refcnt); | ||
340 | sens->sens.ops = &wf_sat_ops; | 315 | sens->sens.ops = &wf_sat_ops; |
341 | sens->sens.name = (char *) (sens + 1); | 316 | sens->sens.name = (char *) (sens + 1); |
342 | snprintf(sens->sens.name, 16, "cpu-power-%d", cpu); | 317 | snprintf(sens->sens.name, 16, "cpu-power-%d", cpu); |
343 | 318 | ||
344 | if (wf_register_sensor(&sens->sens)) { | 319 | if (wf_register_sensor(&sens->sens)) |
345 | atomic_dec(&sat->refcnt); | ||
346 | kfree(sens); | 320 | kfree(sens); |
321 | else { | ||
322 | list_add(&sens->link, &sat->sensors); | ||
323 | kref_get(&sat->ref); | ||
347 | } | 324 | } |
348 | } | 325 | } |
349 | 326 | ||
@@ -353,42 +330,35 @@ static int wf_sat_probe(struct i2c_client *client, | |||
353 | return 0; | 330 | return 0; |
354 | } | 331 | } |
355 | 332 | ||
356 | static int wf_sat_attach(struct i2c_adapter *adapter) | ||
357 | { | ||
358 | struct device_node *busnode, *dev = NULL; | ||
359 | struct pmac_i2c_bus *bus; | ||
360 | |||
361 | bus = pmac_i2c_adapter_to_bus(adapter); | ||
362 | if (bus == NULL) | ||
363 | return -ENODEV; | ||
364 | busnode = pmac_i2c_get_bus_node(bus); | ||
365 | |||
366 | while ((dev = of_get_next_child(busnode, dev)) != NULL) | ||
367 | if (of_device_is_compatible(dev, "smu-sat")) | ||
368 | wf_sat_create(adapter, dev); | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int wf_sat_remove(struct i2c_client *client) | 333 | static int wf_sat_remove(struct i2c_client *client) |
373 | { | 334 | { |
374 | struct wf_sat *sat = i2c_get_clientdata(client); | 335 | struct wf_sat *sat = i2c_get_clientdata(client); |
336 | struct wf_sat_sensor *sens; | ||
375 | 337 | ||
376 | /* XXX TODO */ | 338 | /* release sensors */ |
377 | 339 | while(!list_empty(&sat->sensors)) { | |
340 | sens = list_first_entry(&sat->sensors, | ||
341 | struct wf_sat_sensor, link); | ||
342 | list_del(&sens->link); | ||
343 | wf_unregister_sensor(&sens->sens); | ||
344 | } | ||
378 | sat->i2c = NULL; | 345 | sat->i2c = NULL; |
346 | i2c_set_clientdata(client, NULL); | ||
347 | kref_put(&sat->ref, wf_sat_release); | ||
348 | |||
379 | return 0; | 349 | return 0; |
380 | } | 350 | } |
381 | 351 | ||
382 | static const struct i2c_device_id wf_sat_id[] = { | 352 | static const struct i2c_device_id wf_sat_id[] = { |
383 | { "wf_sat", 0 }, | 353 | { "MAC,smu-sat", 0 }, |
384 | { } | 354 | { } |
385 | }; | 355 | }; |
356 | MODULE_DEVICE_TABLE(i2c, wf_sat_id); | ||
386 | 357 | ||
387 | static struct i2c_driver wf_sat_driver = { | 358 | static struct i2c_driver wf_sat_driver = { |
388 | .driver = { | 359 | .driver = { |
389 | .name = "wf_smu_sat", | 360 | .name = "wf_smu_sat", |
390 | }, | 361 | }, |
391 | .attach_adapter = wf_sat_attach, | ||
392 | .probe = wf_sat_probe, | 362 | .probe = wf_sat_probe, |
393 | .remove = wf_sat_remove, | 363 | .remove = wf_sat_remove, |
394 | .id_table = wf_sat_id, | 364 | .id_table = wf_sat_id, |
@@ -399,15 +369,13 @@ static int __init sat_sensors_init(void) | |||
399 | return i2c_add_driver(&wf_sat_driver); | 369 | return i2c_add_driver(&wf_sat_driver); |
400 | } | 370 | } |
401 | 371 | ||
402 | #if 0 /* uncomment when module_exit() below is uncommented */ | ||
403 | static void __exit sat_sensors_exit(void) | 372 | static void __exit sat_sensors_exit(void) |
404 | { | 373 | { |
405 | i2c_del_driver(&wf_sat_driver); | 374 | i2c_del_driver(&wf_sat_driver); |
406 | } | 375 | } |
407 | #endif | ||
408 | 376 | ||
409 | module_init(sat_sensors_init); | 377 | module_init(sat_sensors_init); |
410 | /*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */ | 378 | module_exit(sat_sensors_exit); |
411 | 379 | ||
412 | MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); | 380 | MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); |
413 | MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control"); | 381 | MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control"); |