aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Boichat <nicolas@boichat.ch>2007-05-08 03:24:52 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:00 -0400
commit6f2fad748ccced5b9313efce2a2c7ae4c04ef564 (patch)
treec626ac5a1d17a130e73b5648580ad20a6b518562
parentee7b9e3706b9c5f90113eb16a1a84a1c01e09f95 (diff)
Apple SMC driver (hardware monitoring and control)
This driver provides support for the Apple System Management Controller, which provides an accelerometer (Apple Sudden Motion Sensor), light sensors, temperature sensors, keyboard backlight control and fan control. Only Intel-based Apple's computers are supported (MacBook Pro, MacBook, MacMini). [bunk@stusta.de: make drivers/hwmon/applesmc.c:backlight_work stati] [khali@linux-fr.org: fix temperature attribute file names] Signed-off-by: Nicolas Boichat <nicolas@boichat.ch> Cc: Jean Delvare <khali@linux-fr.org> Cc: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/hwmon/Kconfig24
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/applesmc.c1339
4 files changed, 1370 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 6d665ac13f99..bb0e832c36ff 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -382,6 +382,12 @@ L: linux-laptop@vger.kernel.org
382W: http://www.canb.auug.org.au/~sfr/ 382W: http://www.canb.auug.org.au/~sfr/
383S: Supported 383S: Supported
384 384
385APPLE SMC DRIVER
386P: Nicolas Boichat
387M: nicolas@boichat.ch
388L: mactel-linux-devel@lists.sourceforge.net
389S: Maintained
390
385APPLETALK NETWORK LAYER 391APPLETALK NETWORK LAYER
386P: Arnaldo Carvalho de Melo 392P: Arnaldo Carvalho de Melo
387M: acme@ghostprotocols.net 393M: acme@ghostprotocols.net
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6d105a1d41b1..25b72a491702 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -594,6 +594,30 @@ config SENSORS_HDAPS
594 Say Y here if you have an applicable laptop and want to experience 594 Say Y here if you have an applicable laptop and want to experience
595 the awesome power of hdaps. 595 the awesome power of hdaps.
596 596
597config SENSORS_APPLESMC
598 tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
599 depends on HWMON && INPUT && X86
600 select NEW_LEDS
601 select LEDS_CLASS
602 default n
603 help
604 This driver provides support for the Apple System Management
605 Controller, which provides an accelerometer (Apple Sudden Motion
606 Sensor), light sensors, temperature sensors, keyboard backlight
607 control and fan control.
608
609 Only Intel-based Apple's computers are supported (MacBook Pro,
610 MacBook, MacMini).
611
612 Data from the different sensors, keyboard backlight control and fan
613 control are accessible via sysfs.
614
615 This driver also provides an absolute input class device, allowing
616 the laptop to act as a pinball machine-esque joystick.
617
618 Say Y here if you have an applicable laptop and want to experience
619 the awesome power of applesmc.
620
597config HWMON_DEBUG_CHIP 621config HWMON_DEBUG_CHIP
598 bool "Hardware Monitoring Chip debugging messages" 622 bool "Hardware Monitoring Chip debugging messages"
599 depends on HWMON 623 depends on HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4165c27a2f25..544f8d8dff4e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
20obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o 20obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
21obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o 21obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
22obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o 22obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
23obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
23obj-$(CONFIG_SENSORS_AMS) += ams/ 24obj-$(CONFIG_SENSORS_AMS) += ams/
24obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o 25obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
25obj-$(CONFIG_SENSORS_DS1621) += ds1621.o 26obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
new file mode 100644
index 000000000000..3215f9c87f32
--- /dev/null
+++ b/drivers/hwmon/applesmc.c
@@ -0,0 +1,1339 @@
1/*
2 * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature
3 * sensors, fan control, keyboard backlight control) used in Intel-based Apple
4 * computers.
5 *
6 * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
7 *
8 * Based on hdaps.c driver:
9 * Copyright (C) 2005 Robert Love <rml@novell.com>
10 * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
11 *
12 * Fan control based on smcFanControl:
13 * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License v2 as published by the
17 * Free Software Foundation.
18 *
19 * This program is distributed in the hope that it will be useful, but WITHOUT
20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
22 * more details.
23 *
24 * You should have received a copy of the GNU General Public License along with
25 * this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29#include <linux/delay.h>
30#include <linux/platform_device.h>
31#include <linux/input.h>
32#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/timer.h>
35#include <linux/dmi.h>
36#include <linux/mutex.h>
37#include <linux/hwmon-sysfs.h>
38#include <asm/io.h>
39#include <linux/leds.h>
40#include <linux/hwmon.h>
41#include <linux/workqueue.h>
42
43/* data port used by Apple SMC */
44#define APPLESMC_DATA_PORT 0x300
45/* command/status port used by Apple SMC */
46#define APPLESMC_CMD_PORT 0x304
47
48#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
49
50#define APPLESMC_MAX_DATA_LENGTH 32
51
52#define APPLESMC_STATUS_MASK 0x0f
53#define APPLESMC_READ_CMD 0x10
54#define APPLESMC_WRITE_CMD 0x11
55#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
56#define APPLESMC_GET_KEY_TYPE_CMD 0x13
57
58#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */
59
60#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */
61#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */
62#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
63
64#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
65
66#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
67#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
68#define MOTION_SENSOR_Z_KEY "MO_Z" /* r-o sp78 (2 bytes) */
69#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */
70
71#define FANS_COUNT "FNum" /* r-o ui8 */
72#define FANS_MANUAL "FS! " /* r-w ui16 */
73#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
74#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
75#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
76#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
77#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
78#define FAN_POSITION "F0ID" /* r-o char[16] */
79
80/*
81 * Temperature sensors keys (sp78 - 2 bytes).
82 * First set for Macbook(Pro), second for Macmini.
83 */
84static const char* temperature_sensors_sets[][13] = {
85 { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
86 "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
87 { "TC0D", "TC0P", NULL }
88};
89
90/* List of keys used to read/write fan speeds */
91static const char* fan_speed_keys[] = {
92 FAN_ACTUAL_SPEED,
93 FAN_MIN_SPEED,
94 FAN_MAX_SPEED,
95 FAN_SAFE_SPEED,
96 FAN_TARGET_SPEED
97};
98
99#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
100#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
101
102#define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
103#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
104#define APPLESMC_INPUT_FLAT 4
105
106#define SENSOR_X 0
107#define SENSOR_Y 1
108#define SENSOR_Z 2
109
110/* Structure to be passed to DMI_MATCH function */
111struct dmi_match_data {
112/* Indicates whether this computer has an accelerometer. */
113 int accelerometer;
114/* Indicates whether this computer has light sensors and keyboard backlight. */
115 int light;
116/* Indicates which temperature sensors set to use. */
117 int temperature_set;
118};
119
120static const int debug;
121static struct platform_device *pdev;
122static s16 rest_x;
123static s16 rest_y;
124static struct timer_list applesmc_timer;
125static struct input_dev *applesmc_idev;
126static struct class_device *hwmon_class_dev;
127
128/* Indicates whether this computer has an accelerometer. */
129static unsigned int applesmc_accelerometer;
130
131/* Indicates whether this computer has light sensors and keyboard backlight. */
132static unsigned int applesmc_light;
133
134/* Indicates which temperature sensors set to use. */
135static unsigned int applesmc_temperature_set;
136
137static struct mutex applesmc_lock;
138
139/*
140 * Last index written to key_at_index sysfs file, and value to use for all other
141 * key_at_index_* sysfs files.
142 */
143static unsigned int key_at_index;
144
145static struct workqueue_struct *applesmc_led_wq;
146
147/*
148 * __wait_status - Wait up to 2ms for the status port to get a certain value
149 * (masked with 0x0f), returning zero if the value is obtained. Callers must
150 * hold applesmc_lock.
151 */
152static int __wait_status(u8 val)
153{
154 unsigned int i;
155
156 val = val & APPLESMC_STATUS_MASK;
157
158 for (i = 0; i < 200; i++) {
159 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
160 if (debug)
161 printk(KERN_DEBUG
162 "Waited %d us for status %x\n",
163 i*10, val);
164 return 0;
165 }
166 udelay(10);
167 }
168
169 printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
170 val, inb(APPLESMC_CMD_PORT));
171
172 return -EIO;
173}
174
175/*
176 * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
177 * Returns zero on success or a negative error on failure. Callers must
178 * hold applesmc_lock.
179 */
180static int applesmc_read_key(const char* key, u8* buffer, u8 len)
181{
182 int i;
183
184 if (len > APPLESMC_MAX_DATA_LENGTH) {
185 printk(KERN_ERR "applesmc_read_key: cannot read more than "
186 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
187 return -EINVAL;
188 }
189
190 outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT);
191 if (__wait_status(0x0c))
192 return -EIO;
193
194 for (i = 0; i < 4; i++) {
195 outb(key[i], APPLESMC_DATA_PORT);
196 if (__wait_status(0x04))
197 return -EIO;
198 }
199 if (debug)
200 printk(KERN_DEBUG "<%s", key);
201
202 outb(len, APPLESMC_DATA_PORT);
203 if (debug)
204 printk(KERN_DEBUG ">%x", len);
205
206 for (i = 0; i < len; i++) {
207 if (__wait_status(0x05))
208 return -EIO;
209 buffer[i] = inb(APPLESMC_DATA_PORT);
210 if (debug)
211 printk(KERN_DEBUG "<%x", buffer[i]);
212 }
213 if (debug)
214 printk(KERN_DEBUG "\n");
215
216 return 0;
217}
218
219/*
220 * applesmc_write_key - writes len bytes from buffer to a given key.
221 * Returns zero on success or a negative error on failure. Callers must
222 * hold applesmc_lock.
223 */
224static int applesmc_write_key(const char* key, u8* buffer, u8 len)
225{
226 int i;
227
228 if (len > APPLESMC_MAX_DATA_LENGTH) {
229 printk(KERN_ERR "applesmc_write_key: cannot write more than "
230 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
231 return -EINVAL;
232 }
233
234 outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT);
235 if (__wait_status(0x0c))
236 return -EIO;
237
238 for (i = 0; i < 4; i++) {
239 outb(key[i], APPLESMC_DATA_PORT);
240 if (__wait_status(0x04))
241 return -EIO;
242 }
243
244 outb(len, APPLESMC_DATA_PORT);
245
246 for (i = 0; i < len; i++) {
247 if (__wait_status(0x04))
248 return -EIO;
249 outb(buffer[i], APPLESMC_DATA_PORT);
250 }
251
252 return 0;
253}
254
255/*
256 * applesmc_get_key_at_index - get key at index, and put the result in key
257 * (char[6]). Returns zero on success or a negative error on failure. Callers
258 * must hold applesmc_lock.
259 */
260static int applesmc_get_key_at_index(int index, char* key)
261{
262 int i;
263 u8 readkey[4];
264 readkey[0] = index >> 24;
265 readkey[1] = index >> 16;
266 readkey[2] = index >> 8;
267 readkey[3] = index;
268
269 outb(APPLESMC_GET_KEY_BY_INDEX_CMD, APPLESMC_CMD_PORT);
270 if (__wait_status(0x0c))
271 return -EIO;
272
273 for (i = 0; i < 4; i++) {
274 outb(readkey[i], APPLESMC_DATA_PORT);
275 if (__wait_status(0x04))
276 return -EIO;
277 }
278
279 outb(4, APPLESMC_DATA_PORT);
280
281 for (i = 0; i < 4; i++) {
282 if (__wait_status(0x05))
283 return -EIO;
284 key[i] = inb(APPLESMC_DATA_PORT);
285 }
286 key[4] = 0;
287
288 return 0;
289}
290
291/*
292 * applesmc_get_key_type - get key type, and put the result in type (char[6]).
293 * Returns zero on success or a negative error on failure. Callers must
294 * hold applesmc_lock.
295 */
296static int applesmc_get_key_type(char* key, char* type)
297{
298 int i;
299
300 outb(APPLESMC_GET_KEY_TYPE_CMD, APPLESMC_CMD_PORT);
301 if (__wait_status(0x0c))
302 return -EIO;
303
304 for (i = 0; i < 4; i++) {
305 outb(key[i], APPLESMC_DATA_PORT);
306 if (__wait_status(0x04))
307 return -EIO;
308 }
309
310 outb(5, APPLESMC_DATA_PORT);
311
312 for (i = 0; i < 6; i++) {
313 if (__wait_status(0x05))
314 return -EIO;
315 type[i] = inb(APPLESMC_DATA_PORT);
316 }
317 type[5] = 0;
318
319 return 0;
320}
321
322/*
323 * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
324 * hold applesmc_lock.
325 */
326static int applesmc_read_motion_sensor(int index, s16* value)
327{
328 u8 buffer[2];
329 int ret;
330
331 switch (index) {
332 case SENSOR_X:
333 ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
334 break;
335 case SENSOR_Y:
336 ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
337 break;
338 case SENSOR_Z:
339 ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
340 break;
341 default:
342 ret = -EINVAL;
343 }
344
345 *value = ((s16)buffer[0] << 8) | buffer[1];
346
347 return ret;
348}
349
350/*
351 * applesmc_device_init - initialize the accelerometer. Returns zero on success
352 * and negative error code on failure. Can sleep.
353 */
354static int applesmc_device_init(void)
355{
356 int total, ret = -ENXIO;
357 u8 buffer[2];
358
359 if (!applesmc_accelerometer)
360 return 0;
361
362 mutex_lock(&applesmc_lock);
363
364 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
365 if (debug)
366 printk(KERN_DEBUG "applesmc try %d\n", total);
367 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
368 (buffer[0] != 0x00 || buffer[1] != 0x00)) {
369 if (total == INIT_TIMEOUT_MSECS) {
370 printk(KERN_DEBUG "applesmc: device has"
371 " already been initialized"
372 " (0x%02x, 0x%02x).\n",
373 buffer[0], buffer[1]);
374 } else {
375 printk(KERN_DEBUG "applesmc: device"
376 " successfully initialized"
377 " (0x%02x, 0x%02x).\n",
378 buffer[0], buffer[1]);
379 }
380 ret = 0;
381 goto out;
382 }
383 buffer[0] = 0xe0;
384 buffer[1] = 0x00;
385 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
386 msleep(INIT_WAIT_MSECS);
387 }
388
389 printk(KERN_WARNING "applesmc: failed to init the device\n");
390
391out:
392 mutex_unlock(&applesmc_lock);
393 return ret;
394}
395
396/*
397 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
398 * applesmc_lock.
399 */
400static int applesmc_get_fan_count(void)
401{
402 int ret;
403 u8 buffer[1];
404
405 mutex_lock(&applesmc_lock);
406
407 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
408
409 mutex_unlock(&applesmc_lock);
410 if (ret)
411 return ret;
412 else
413 return buffer[0];
414}
415
416/* Device model stuff */
417static int applesmc_probe(struct platform_device *dev)
418{
419 int ret;
420
421 ret = applesmc_device_init();
422 if (ret)
423 return ret;
424
425 printk(KERN_INFO "applesmc: device successfully initialized.\n");
426 return 0;
427}
428
429static int applesmc_resume(struct platform_device *dev)
430{
431 return applesmc_device_init();
432}
433
434static struct platform_driver applesmc_driver = {
435 .probe = applesmc_probe,
436 .resume = applesmc_resume,
437 .driver = {
438 .name = "applesmc",
439 .owner = THIS_MODULE,
440 },
441};
442
443/*
444 * applesmc_calibrate - Set our "resting" values. Callers must
445 * hold applesmc_lock.
446 */
447static void applesmc_calibrate(void)
448{
449 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
450 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
451 rest_x = -rest_x;
452}
453
454static int applesmc_idev_open(struct input_dev *dev)
455{
456 add_timer(&applesmc_timer);
457
458 return 0;
459}
460
461static void applesmc_idev_close(struct input_dev *dev)
462{
463 del_timer_sync(&applesmc_timer);
464}
465
466static void applesmc_idev_poll(unsigned long unused)
467{
468 s16 x, y;
469
470 /* Cannot sleep. Try nonblockingly. If we fail, try again later. */
471 if (!mutex_trylock(&applesmc_lock)) {
472 mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
473 return;
474 }
475
476 if (applesmc_read_motion_sensor(SENSOR_X, &x))
477 goto out;
478 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
479 goto out;
480
481 x = -x;
482 input_report_abs(applesmc_idev, ABS_X, x - rest_x);
483 input_report_abs(applesmc_idev, ABS_Y, y - rest_y);
484 input_sync(applesmc_idev);
485
486out:
487 mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
488
489 mutex_unlock(&applesmc_lock);
490}
491
492/* Sysfs Files */
493
494static ssize_t applesmc_position_show(struct device *dev,
495 struct device_attribute *attr, char *buf)
496{
497 int ret;
498 s16 x, y, z;
499
500 mutex_lock(&applesmc_lock);
501
502 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
503 if (ret)
504 goto out;
505 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
506 if (ret)
507 goto out;
508 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
509 if (ret)
510 goto out;
511
512out:
513 mutex_unlock(&applesmc_lock);
514 if (ret)
515 return ret;
516 else
517 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
518}
519
520static ssize_t applesmc_light_show(struct device *dev,
521 struct device_attribute *attr, char *sysfsbuf)
522{
523 int ret;
524 u8 left = 0, right = 0;
525 u8 buffer[6];
526
527 mutex_lock(&applesmc_lock);
528
529 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, 6);
530 left = buffer[2];
531 if (ret)
532 goto out;
533 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, 6);
534 right = buffer[2];
535
536out:
537 mutex_unlock(&applesmc_lock);
538 if (ret)
539 return ret;
540 else
541 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
542}
543
544/* Displays degree Celsius * 1000 */
545static ssize_t applesmc_show_temperature(struct device *dev,
546 struct device_attribute *devattr, char *sysfsbuf)
547{
548 int ret;
549 u8 buffer[2];
550 unsigned int temp;
551 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
552 const char* key =
553 temperature_sensors_sets[applesmc_temperature_set][attr->index];
554
555 mutex_lock(&applesmc_lock);
556
557 ret = applesmc_read_key(key, buffer, 2);
558 temp = buffer[0]*1000;
559 temp += (buffer[1] >> 6) * 250;
560
561 mutex_unlock(&applesmc_lock);
562
563 if (ret)
564 return ret;
565 else
566 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
567}
568
569static ssize_t applesmc_show_fan_speed(struct device *dev,
570 struct device_attribute *attr, char *sysfsbuf)
571{
572 int ret;
573 unsigned int speed = 0;
574 char newkey[5];
575 u8 buffer[2];
576 struct sensor_device_attribute_2 *sensor_attr =
577 to_sensor_dev_attr_2(attr);
578
579 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
580 newkey[1] = '0' + sensor_attr->index;
581 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
582 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
583 newkey[4] = 0;
584
585 mutex_lock(&applesmc_lock);
586
587 ret = applesmc_read_key(newkey, buffer, 2);
588 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
589
590 mutex_unlock(&applesmc_lock);
591 if (ret)
592 return ret;
593 else
594 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
595}
596
597static ssize_t applesmc_store_fan_speed(struct device *dev,
598 struct device_attribute *attr,
599 const char *sysfsbuf, size_t count)
600{
601 int ret;
602 u32 speed;
603 char newkey[5];
604 u8 buffer[2];
605 struct sensor_device_attribute_2 *sensor_attr =
606 to_sensor_dev_attr_2(attr);
607
608 speed = simple_strtoul(sysfsbuf, NULL, 10);
609
610 if (speed > 0x4000) /* Bigger than a 14-bit value */
611 return -EINVAL;
612
613 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
614 newkey[1] = '0' + sensor_attr->index;
615 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
616 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
617 newkey[4] = 0;
618
619 mutex_lock(&applesmc_lock);
620
621 buffer[0] = (speed >> 6) & 0xff;
622 buffer[1] = (speed << 2) & 0xff;
623 ret = applesmc_write_key(newkey, buffer, 2);
624
625 mutex_unlock(&applesmc_lock);
626 if (ret)
627 return ret;
628 else
629 return count;
630}
631
632static ssize_t applesmc_show_fan_manual(struct device *dev,
633 struct device_attribute *devattr, char *sysfsbuf)
634{
635 int ret;
636 u16 manual = 0;
637 u8 buffer[2];
638 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
639
640 mutex_lock(&applesmc_lock);
641
642 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
643 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
644
645 mutex_unlock(&applesmc_lock);
646 if (ret)
647 return ret;
648 else
649 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
650}
651
652static ssize_t applesmc_store_fan_manual(struct device *dev,
653 struct device_attribute *devattr,
654 const char *sysfsbuf, size_t count)
655{
656 int ret;
657 u8 buffer[2];
658 u32 input;
659 u16 val;
660 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
661
662 input = simple_strtoul(sysfsbuf, NULL, 10);
663
664 mutex_lock(&applesmc_lock);
665
666 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
667 val = (buffer[0] << 8 | buffer[1]);
668 if (ret)
669 goto out;
670
671 if (input)
672 val = val | (0x01 << attr->index);
673 else
674 val = val & ~(0x01 << attr->index);
675
676 buffer[0] = (val >> 8) & 0xFF;
677 buffer[1] = val & 0xFF;
678
679 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
680
681out:
682 mutex_unlock(&applesmc_lock);
683 if (ret)
684 return ret;
685 else
686 return count;
687}
688
689static ssize_t applesmc_show_fan_position(struct device *dev,
690 struct device_attribute *attr, char *sysfsbuf)
691{
692 int ret;
693 char newkey[5];
694 u8 buffer[17];
695 struct sensor_device_attribute_2 *sensor_attr =
696 to_sensor_dev_attr_2(attr);
697
698 newkey[0] = FAN_POSITION[0];
699 newkey[1] = '0' + sensor_attr->index;
700 newkey[2] = FAN_POSITION[2];
701 newkey[3] = FAN_POSITION[3];
702 newkey[4] = 0;
703
704 mutex_lock(&applesmc_lock);
705
706 ret = applesmc_read_key(newkey, buffer, 16);
707 buffer[16] = 0;
708
709 mutex_unlock(&applesmc_lock);
710 if (ret)
711 return ret;
712 else
713 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
714}
715
716static ssize_t applesmc_calibrate_show(struct device *dev,
717 struct device_attribute *attr, char *sysfsbuf)
718{
719 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
720}
721
722static ssize_t applesmc_calibrate_store(struct device *dev,
723 struct device_attribute *attr, const char *sysfsbuf, size_t count)
724{
725 mutex_lock(&applesmc_lock);
726 applesmc_calibrate();
727 mutex_unlock(&applesmc_lock);
728
729 return count;
730}
731
732/* Store the next backlight value to be written by the work */
733static unsigned int backlight_value;
734
735static void applesmc_backlight_set(struct work_struct *work)
736{
737 u8 buffer[2];
738
739 mutex_lock(&applesmc_lock);
740 buffer[0] = backlight_value;
741 buffer[1] = 0x00;
742 applesmc_write_key(BACKLIGHT_KEY, buffer, 2);
743 mutex_unlock(&applesmc_lock);
744}
745static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
746
747static void applesmc_brightness_set(struct led_classdev *led_cdev,
748 enum led_brightness value)
749{
750 int ret;
751
752 backlight_value = value;
753 ret = queue_work(applesmc_led_wq, &backlight_work);
754
755 if (debug && (!ret))
756 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
757}
758
759static ssize_t applesmc_key_count_show(struct device *dev,
760 struct device_attribute *attr, char *sysfsbuf)
761{
762 int ret;
763 u8 buffer[4];
764 u32 count;
765
766 mutex_lock(&applesmc_lock);
767
768 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
769 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
770 ((u32)buffer[2]<<8) + buffer[3];
771
772 mutex_unlock(&applesmc_lock);
773 if (ret)
774 return ret;
775 else
776 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
777}
778
779static ssize_t applesmc_key_at_index_read_show(struct device *dev,
780 struct device_attribute *attr, char *sysfsbuf)
781{
782 char key[5];
783 char info[6];
784 int ret;
785
786 mutex_lock(&applesmc_lock);
787
788 ret = applesmc_get_key_at_index(key_at_index, key);
789
790 if (ret || !key[0]) {
791 mutex_unlock(&applesmc_lock);
792
793 return -EINVAL;
794 }
795
796 ret = applesmc_get_key_type(key, info);
797
798 if (ret) {
799 mutex_unlock(&applesmc_lock);
800
801 return ret;
802 }
803
804 /*
805 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
806 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
807 */
808 ret = applesmc_read_key(key, sysfsbuf, info[0]);
809
810 mutex_unlock(&applesmc_lock);
811
812 if (!ret) {
813 return info[0];
814 }
815 else {
816 return ret;
817 }
818}
819
820static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
821 struct device_attribute *attr, char *sysfsbuf)
822{
823 char key[5];
824 char info[6];
825 int ret;
826
827 mutex_lock(&applesmc_lock);
828
829 ret = applesmc_get_key_at_index(key_at_index, key);
830
831 if (ret || !key[0]) {
832 mutex_unlock(&applesmc_lock);
833
834 return -EINVAL;
835 }
836
837 ret = applesmc_get_key_type(key, info);
838
839 mutex_unlock(&applesmc_lock);
840
841 if (!ret)
842 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
843 else
844 return ret;
845}
846
847static ssize_t applesmc_key_at_index_type_show(struct device *dev,
848 struct device_attribute *attr, char *sysfsbuf)
849{
850 char key[5];
851 char info[6];
852 int ret;
853
854 mutex_lock(&applesmc_lock);
855
856 ret = applesmc_get_key_at_index(key_at_index, key);
857
858 if (ret || !key[0]) {
859 mutex_unlock(&applesmc_lock);
860
861 return -EINVAL;
862 }
863
864 ret = applesmc_get_key_type(key, info);
865
866 mutex_unlock(&applesmc_lock);
867
868 if (!ret)
869 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
870 else
871 return ret;
872}
873
874static ssize_t applesmc_key_at_index_name_show(struct device *dev,
875 struct device_attribute *attr, char *sysfsbuf)
876{
877 char key[5];
878 int ret;
879
880 mutex_lock(&applesmc_lock);
881
882 ret = applesmc_get_key_at_index(key_at_index, key);
883
884 mutex_unlock(&applesmc_lock);
885
886 if (!ret && key[0])
887 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
888 else
889 return -EINVAL;
890}
891
892static ssize_t applesmc_key_at_index_show(struct device *dev,
893 struct device_attribute *attr, char *sysfsbuf)
894{
895 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
896}
897
898static ssize_t applesmc_key_at_index_store(struct device *dev,
899 struct device_attribute *attr, const char *sysfsbuf, size_t count)
900{
901 mutex_lock(&applesmc_lock);
902
903 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
904
905 mutex_unlock(&applesmc_lock);
906
907 return count;
908}
909
910static struct led_classdev applesmc_backlight = {
911 .name = "smc:kbd_backlight",
912 .default_trigger = "nand-disk",
913 .brightness_set = applesmc_brightness_set,
914};
915
916static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
917static DEVICE_ATTR(calibrate, 0644,
918 applesmc_calibrate_show, applesmc_calibrate_store);
919
920static struct attribute *accelerometer_attributes[] = {
921 &dev_attr_position.attr,
922 &dev_attr_calibrate.attr,
923 NULL
924};
925
926static const struct attribute_group accelerometer_attributes_group =
927 { .attrs = accelerometer_attributes };
928
929static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
930
931static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
932static DEVICE_ATTR(key_at_index, 0644,
933 applesmc_key_at_index_show, applesmc_key_at_index_store);
934static DEVICE_ATTR(key_at_index_name, 0444,
935 applesmc_key_at_index_name_show, NULL);
936static DEVICE_ATTR(key_at_index_type, 0444,
937 applesmc_key_at_index_type_show, NULL);
938static DEVICE_ATTR(key_at_index_data_length, 0444,
939 applesmc_key_at_index_data_length_show, NULL);
940static DEVICE_ATTR(key_at_index_data, 0444,
941 applesmc_key_at_index_read_show, NULL);
942
943static struct attribute *key_enumeration_attributes[] = {
944 &dev_attr_key_count.attr,
945 &dev_attr_key_at_index.attr,
946 &dev_attr_key_at_index_name.attr,
947 &dev_attr_key_at_index_type.attr,
948 &dev_attr_key_at_index_data_length.attr,
949 &dev_attr_key_at_index_data.attr,
950 NULL
951};
952
953static const struct attribute_group key_enumeration_group =
954 { .attrs = key_enumeration_attributes };
955
956/*
957 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
958 * - show actual speed
959 * - show/store minimum speed
960 * - show maximum speed
961 * - show safe speed
962 * - show/store target speed
963 * - show/store manual mode
964 */
965#define sysfs_fan_speeds_offset(offset) \
966static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
967 applesmc_show_fan_speed, NULL, 0, offset-1); \
968\
969static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
970 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
971\
972static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
973 applesmc_show_fan_speed, NULL, 2, offset-1); \
974\
975static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
976 applesmc_show_fan_speed, NULL, 3, offset-1); \
977\
978static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
979 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
980\
981static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
982 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
983\
984static SENSOR_DEVICE_ATTR(fan##offset##_position, S_IRUGO, \
985 applesmc_show_fan_position, NULL, offset-1); \
986\
987static struct attribute *fan##offset##_attributes[] = { \
988 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
989 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
990 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
991 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
992 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
993 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
994 &sensor_dev_attr_fan##offset##_position.dev_attr.attr, \
995 NULL \
996};
997
998/*
999 * Create the needed functions for each fan using the macro defined above
1000 * (2 fans are supported)
1001 */
1002sysfs_fan_speeds_offset(1);
1003sysfs_fan_speeds_offset(2);
1004
1005static const struct attribute_group fan_attribute_groups[] = {
1006 { .attrs = fan1_attributes },
1007 { .attrs = fan2_attributes }
1008};
1009
1010/*
1011 * Temperature sensors sysfs entries.
1012 */
1013static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1014 applesmc_show_temperature, NULL, 0);
1015static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1016 applesmc_show_temperature, NULL, 1);
1017static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1018 applesmc_show_temperature, NULL, 2);
1019static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1020 applesmc_show_temperature, NULL, 3);
1021static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1022 applesmc_show_temperature, NULL, 4);
1023static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1024 applesmc_show_temperature, NULL, 5);
1025static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1026 applesmc_show_temperature, NULL, 6);
1027static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1028 applesmc_show_temperature, NULL, 7);
1029static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1030 applesmc_show_temperature, NULL, 8);
1031static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1032 applesmc_show_temperature, NULL, 9);
1033static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1034 applesmc_show_temperature, NULL, 10);
1035static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1036 applesmc_show_temperature, NULL, 11);
1037
1038static struct attribute *temperature_attributes[] = {
1039 &sensor_dev_attr_temp1_input.dev_attr.attr,
1040 &sensor_dev_attr_temp2_input.dev_attr.attr,
1041 &sensor_dev_attr_temp3_input.dev_attr.attr,
1042 &sensor_dev_attr_temp4_input.dev_attr.attr,
1043 &sensor_dev_attr_temp5_input.dev_attr.attr,
1044 &sensor_dev_attr_temp6_input.dev_attr.attr,
1045 &sensor_dev_attr_temp7_input.dev_attr.attr,
1046 &sensor_dev_attr_temp8_input.dev_attr.attr,
1047 &sensor_dev_attr_temp9_input.dev_attr.attr,
1048 &sensor_dev_attr_temp10_input.dev_attr.attr,
1049 &sensor_dev_attr_temp11_input.dev_attr.attr,
1050 &sensor_dev_attr_temp12_input.dev_attr.attr,
1051 NULL
1052};
1053
1054static const struct attribute_group temperature_attributes_group =
1055 { .attrs = temperature_attributes };
1056
1057/* Module stuff */
1058
1059/*
1060 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1061 */
1062static int applesmc_dmi_match(struct dmi_system_id *id)
1063{
1064 int i = 0;
1065 struct dmi_match_data* dmi_data = id->driver_data;
1066 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1067 applesmc_accelerometer = dmi_data->accelerometer;
1068 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1069 applesmc_accelerometer ? "with" : "without");
1070 applesmc_light = dmi_data->light;
1071 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1072 applesmc_light ? "with" : "without");
1073
1074 applesmc_temperature_set = dmi_data->temperature_set;
1075 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1076 i++;
1077 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1078 return 1;
1079}
1080
1081/* Create accelerometer ressources */
1082static int applesmc_create_accelerometer(void)
1083{
1084 int ret;
1085
1086 ret = sysfs_create_group(&pdev->dev.kobj,
1087 &accelerometer_attributes_group);
1088 if (ret)
1089 goto out;
1090
1091 applesmc_idev = input_allocate_device();
1092 if (!applesmc_idev) {
1093 ret = -ENOMEM;
1094 goto out_sysfs;
1095 }
1096
1097 /* initial calibrate for the input device */
1098 applesmc_calibrate();
1099
1100 /* initialize the input class */
1101 applesmc_idev->name = "applesmc";
1102 applesmc_idev->id.bustype = BUS_HOST;
1103 applesmc_idev->cdev.dev = &pdev->dev;
1104 applesmc_idev->evbit[0] = BIT(EV_ABS);
1105 applesmc_idev->open = applesmc_idev_open;
1106 applesmc_idev->close = applesmc_idev_close;
1107 input_set_abs_params(applesmc_idev, ABS_X,
1108 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1109 input_set_abs_params(applesmc_idev, ABS_Y,
1110 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1111
1112 ret = input_register_device(applesmc_idev);
1113 if (ret)
1114 goto out_idev;
1115
1116 /* start up our timer for the input device */
1117 init_timer(&applesmc_timer);
1118 applesmc_timer.function = applesmc_idev_poll;
1119 applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD;
1120
1121 return 0;
1122
1123out_idev:
1124 input_free_device(applesmc_idev);
1125
1126out_sysfs:
1127 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1128
1129out:
1130 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1131 return ret;
1132}
1133
1134/* Release all ressources used by the accelerometer */
1135static void applesmc_release_accelerometer(void)
1136{
1137 del_timer_sync(&applesmc_timer);
1138 input_unregister_device(applesmc_idev);
1139 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1140}
1141
1142static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1143/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1144 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
1145/* MacBook: accelerometer and temperature set 0 */
1146 { .accelerometer = 1, .light = 0, .temperature_set = 0 },
1147/* MacBook: temperature set 1 */
1148 { .accelerometer = 0, .light = 0, .temperature_set = 1 }
1149};
1150
1151/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1152 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1153static __initdata struct dmi_system_id applesmc_whitelist[] = {
1154 { applesmc_dmi_match, "Apple MacBook Pro", {
1155 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1156 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
1157 (void*)&applesmc_dmi_data[0]},
1158 { applesmc_dmi_match, "Apple MacBook", {
1159 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1160 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
1161 (void*)&applesmc_dmi_data[1]},
1162 { applesmc_dmi_match, "Apple Macmini", {
1163 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1164 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
1165 (void*)&applesmc_dmi_data[2]},
1166 { .ident = NULL }
1167};
1168
1169static int __init applesmc_init(void)
1170{
1171 int ret;
1172 int count;
1173 int i;
1174
1175 mutex_init(&applesmc_lock);
1176
1177 if (!dmi_check_system(applesmc_whitelist)) {
1178 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1179 ret = -ENODEV;
1180 goto out;
1181 }
1182
1183 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1184 "applesmc")) {
1185 ret = -ENXIO;
1186 goto out;
1187 }
1188
1189 ret = platform_driver_register(&applesmc_driver);
1190 if (ret)
1191 goto out_region;
1192
1193 pdev = platform_device_register_simple("applesmc", -1, NULL, 0);
1194 if (IS_ERR(pdev)) {
1195 ret = PTR_ERR(pdev);
1196 goto out_driver;
1197 }
1198
1199 /* Create key enumeration sysfs files */
1200 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1201 if (ret)
1202 goto out_device;
1203
1204 /* create fan files */
1205 count = applesmc_get_fan_count();
1206 if (count < 0) {
1207 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
1208 } else {
1209 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1210
1211 switch (count) {
1212 default:
1213 printk(KERN_WARNING "applesmc: More than 2 fans found,"
1214 " but at most 2 fans are supported"
1215 " by the driver.\n");
1216 case 2:
1217 ret = sysfs_create_group(&pdev->dev.kobj,
1218 &fan_attribute_groups[1]);
1219 if (ret)
1220 goto out_key_enumeration;
1221 case 1:
1222 ret = sysfs_create_group(&pdev->dev.kobj,
1223 &fan_attribute_groups[0]);
1224 if (ret)
1225 goto out_fan_1;
1226 case 0:
1227 ;
1228 }
1229 }
1230
1231 for (i = 0;
1232 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1233 i++) {
1234 if (temperature_attributes[i] == NULL) {
1235 printk(KERN_ERR "applesmc: More temperature sensors "
1236 "in temperature_sensors_sets (at least %i)"
1237 "than available sysfs files in "
1238 "temperature_attributes (%i), please report "
1239 "this bug.\n", i, i-1);
1240 goto out_temperature;
1241 }
1242 ret = sysfs_create_file(&pdev->dev.kobj,
1243 temperature_attributes[i]);
1244 if (ret)
1245 goto out_temperature;
1246 }
1247
1248 if (applesmc_accelerometer) {
1249 ret = applesmc_create_accelerometer();
1250 if (ret)
1251 goto out_temperature;
1252 }
1253
1254 if (applesmc_light) {
1255 /* Add light sensor file */
1256 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1257 if (ret)
1258 goto out_accelerometer;
1259
1260 /* Create the workqueue */
1261 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1262 if (!applesmc_led_wq) {
1263 ret = -ENOMEM;
1264 goto out_light_sysfs;
1265 }
1266
1267 /* register as a led device */
1268 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1269 if (ret < 0)
1270 goto out_light_wq;
1271 }
1272
1273 hwmon_class_dev = hwmon_device_register(&pdev->dev);
1274 if (IS_ERR(hwmon_class_dev)) {
1275 ret = PTR_ERR(hwmon_class_dev);
1276 goto out_light_ledclass;
1277 }
1278
1279 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1280
1281 return 0;
1282
1283out_light_ledclass:
1284 if (applesmc_light)
1285 led_classdev_unregister(&applesmc_backlight);
1286out_light_wq:
1287 if (applesmc_light)
1288 destroy_workqueue(applesmc_led_wq);
1289out_light_sysfs:
1290 if (applesmc_light)
1291 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1292out_accelerometer:
1293 if (applesmc_accelerometer)
1294 applesmc_release_accelerometer();
1295out_temperature:
1296 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1297 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1298out_fan_1:
1299 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1300out_key_enumeration:
1301 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
1302out_device:
1303 platform_device_unregister(pdev);
1304out_driver:
1305 platform_driver_unregister(&applesmc_driver);
1306out_region:
1307 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1308out:
1309 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1310 return ret;
1311}
1312
1313static void __exit applesmc_exit(void)
1314{
1315 hwmon_device_unregister(hwmon_class_dev);
1316 if (applesmc_light) {
1317 led_classdev_unregister(&applesmc_backlight);
1318 destroy_workqueue(applesmc_led_wq);
1319 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1320 }
1321 if (applesmc_accelerometer)
1322 applesmc_release_accelerometer();
1323 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1324 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1325 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1326 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
1327 platform_device_unregister(pdev);
1328 platform_driver_unregister(&applesmc_driver);
1329 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1330
1331 printk(KERN_INFO "applesmc: driver unloaded.\n");
1332}
1333
1334module_init(applesmc_init);
1335module_exit(applesmc_exit);
1336
1337MODULE_AUTHOR("Nicolas Boichat");
1338MODULE_DESCRIPTION("Apple SMC");
1339MODULE_LICENSE("GPL v2");