blob: e301862365889e1e2750d1514807a45d6489644b [file] [log] [blame]
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001/*
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>
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040031#include <linux/input-polldev.h>
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070032#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
Henrik Rydberg8c9398d2008-10-18 20:27:43 -070052#define APPLESMC_MIN_WAIT 0x0040
53#define APPLESMC_MAX_WAIT 0x8000
54
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070055#define APPLESMC_STATUS_MASK 0x0f
56#define APPLESMC_READ_CMD 0x10
57#define APPLESMC_WRITE_CMD 0x11
58#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
59#define APPLESMC_GET_KEY_TYPE_CMD 0x13
60
61#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */
62
Henrik Rydberg8bd1a122008-10-18 20:27:39 -070063#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6-10 bytes) */
64#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6-10 bytes) */
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040065#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070066
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040067#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070068
69#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
70#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
71#define MOTION_SENSOR_Z_KEY "MO_Z" /* r-o sp78 (2 bytes) */
72#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */
73
74#define FANS_COUNT "FNum" /* r-o ui8 */
75#define FANS_MANUAL "FS! " /* r-w ui16 */
76#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
77#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
78#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
79#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
80#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
81#define FAN_POSITION "F0ID" /* r-o char[16] */
82
83/*
84 * Temperature sensors keys (sp78 - 2 bytes).
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070085 */
René Rebe8de57702007-10-16 14:19:20 -070086static const char* temperature_sensors_sets[][36] = {
Martin Szulecki1bed24b2007-07-09 11:41:36 -070087/* Set 0: Macbook Pro */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070088 { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
89 "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080090/* Set 1: Macbook2 set */
91 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
92 "Th0S", "Th1H", NULL },
93/* Set 2: Macbook set */
Martin Szulecki1bed24b2007-07-09 11:41:36 -070094 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
95 "Th1H", "Ts0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080096/* Set 3: Macmini set */
René Rebe8de57702007-10-16 14:19:20 -070097 { "TC0D", "TC0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080098/* Set 4: Mac Pro (2 x Quad-Core) */
René Rebe8de57702007-10-16 14:19:20 -070099 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
100 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
101 "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
102 "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
103 "TM9S", "TN0H", "TS0C", NULL },
Roberto De Ioris9f86f282008-08-15 00:40:30 -0700104/* Set 5: iMac */
105 { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
106 "Tp0C", NULL },
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -0700107/* Set 6: Macbook3 set */
108 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
109 "Th0S", "Th1H", NULL },
Henrik Rydbergf5274c92008-10-18 20:27:40 -0700110/* Set 7: Macbook Air */
111 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
112 "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
Henrik Rydbergd7549902008-10-18 20:27:41 -0700113/* Set 8: Macbook Pro 4,1 (Penryn) */
114 { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
115 "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -0700116/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
117 { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
118 "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -0800119/* Set 10: iMac 5,1 */
120 { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL },
Henrik Rydberg181209a12008-11-06 12:53:20 -0800121/* Set 11: Macbook 5,1 */
122 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P",
123 "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL },
Henrik Rydberga6660322008-11-06 12:53:21 -0800124/* Set 12: Macbook Pro 5,1 */
125 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
126 "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0",
127 "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL },
Henrik Rydbergeefc4882008-11-06 12:53:22 -0800128/* Set 13: iMac 8,1 */
129 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
130 "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -0800131/* Set 14: iMac 6,1 */
132 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
133 "TO0P", "Tp0P", NULL },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -0800134/* Set 15: MacBook Air 2,1 */
135 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0",
136 "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P",
137 "Ts0S", NULL },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700138};
139
140/* List of keys used to read/write fan speeds */
141static const char* fan_speed_keys[] = {
142 FAN_ACTUAL_SPEED,
143 FAN_MIN_SPEED,
144 FAN_MAX_SPEED,
145 FAN_SAFE_SPEED,
146 FAN_TARGET_SPEED
147};
148
149#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
150#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
151
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400152#define APPLESMC_POLL_INTERVAL 50 /* msecs */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700153#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
154#define APPLESMC_INPUT_FLAT 4
155
156#define SENSOR_X 0
157#define SENSOR_Y 1
158#define SENSOR_Z 2
159
160/* Structure to be passed to DMI_MATCH function */
161struct dmi_match_data {
162/* Indicates whether this computer has an accelerometer. */
163 int accelerometer;
164/* Indicates whether this computer has light sensors and keyboard backlight. */
165 int light;
166/* Indicates which temperature sensors set to use. */
167 int temperature_set;
168};
169
170static const int debug;
171static struct platform_device *pdev;
172static s16 rest_x;
173static s16 rest_y;
Tony Jones1beeffe2007-08-20 13:46:20 -0700174static struct device *hwmon_dev;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400175static struct input_polled_dev *applesmc_idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700176
177/* Indicates whether this computer has an accelerometer. */
178static unsigned int applesmc_accelerometer;
179
180/* Indicates whether this computer has light sensors and keyboard backlight. */
181static unsigned int applesmc_light;
182
183/* Indicates which temperature sensors set to use. */
184static unsigned int applesmc_temperature_set;
185
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400186static DEFINE_MUTEX(applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700187
188/*
189 * Last index written to key_at_index sysfs file, and value to use for all other
190 * key_at_index_* sysfs files.
191 */
192static unsigned int key_at_index;
193
194static struct workqueue_struct *applesmc_led_wq;
195
196/*
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700197 * __wait_status - Wait up to 32ms for the status port to get a certain value
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700198 * (masked with 0x0f), returning zero if the value is obtained. Callers must
199 * hold applesmc_lock.
200 */
201static int __wait_status(u8 val)
202{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700203 int us;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700204
205 val = val & APPLESMC_STATUS_MASK;
206
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700207 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
208 udelay(us);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700209 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
210 if (debug)
211 printk(KERN_DEBUG
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700212 "Waited %d us for status %x\n",
213 2 * us - APPLESMC_MIN_WAIT, val);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700214 return 0;
215 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700216 }
217
218 printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
219 val, inb(APPLESMC_CMD_PORT));
220
221 return -EIO;
222}
223
224/*
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700225 * special treatment of command port - on newer macbooks, it seems necessary
226 * to resend the command byte before polling the status again. Callers must
227 * hold applesmc_lock.
228 */
229static int send_command(u8 cmd)
230{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700231 int us;
232 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700233 outb(cmd, APPLESMC_CMD_PORT);
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700234 udelay(us);
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700235 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
236 return 0;
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700237 }
238 printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
239 cmd, inb(APPLESMC_CMD_PORT));
240 return -EIO;
241}
242
243/*
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700244 * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
245 * Returns zero on success or a negative error on failure. Callers must
246 * hold applesmc_lock.
247 */
248static int applesmc_read_key(const char* key, u8* buffer, u8 len)
249{
250 int i;
251
252 if (len > APPLESMC_MAX_DATA_LENGTH) {
253 printk(KERN_ERR "applesmc_read_key: cannot read more than "
254 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
255 return -EINVAL;
256 }
257
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700258 if (send_command(APPLESMC_READ_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700259 return -EIO;
260
261 for (i = 0; i < 4; i++) {
262 outb(key[i], APPLESMC_DATA_PORT);
263 if (__wait_status(0x04))
264 return -EIO;
265 }
266 if (debug)
267 printk(KERN_DEBUG "<%s", key);
268
269 outb(len, APPLESMC_DATA_PORT);
270 if (debug)
271 printk(KERN_DEBUG ">%x", len);
272
273 for (i = 0; i < len; i++) {
274 if (__wait_status(0x05))
275 return -EIO;
276 buffer[i] = inb(APPLESMC_DATA_PORT);
277 if (debug)
278 printk(KERN_DEBUG "<%x", buffer[i]);
279 }
280 if (debug)
281 printk(KERN_DEBUG "\n");
282
283 return 0;
284}
285
286/*
287 * applesmc_write_key - writes len bytes from buffer to a given key.
288 * Returns zero on success or a negative error on failure. Callers must
289 * hold applesmc_lock.
290 */
291static int applesmc_write_key(const char* key, u8* buffer, u8 len)
292{
293 int i;
294
295 if (len > APPLESMC_MAX_DATA_LENGTH) {
296 printk(KERN_ERR "applesmc_write_key: cannot write more than "
297 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
298 return -EINVAL;
299 }
300
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700301 if (send_command(APPLESMC_WRITE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700302 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(len, APPLESMC_DATA_PORT);
311
312 for (i = 0; i < len; i++) {
313 if (__wait_status(0x04))
314 return -EIO;
315 outb(buffer[i], APPLESMC_DATA_PORT);
316 }
317
318 return 0;
319}
320
321/*
322 * applesmc_get_key_at_index - get key at index, and put the result in key
323 * (char[6]). Returns zero on success or a negative error on failure. Callers
324 * must hold applesmc_lock.
325 */
326static int applesmc_get_key_at_index(int index, char* key)
327{
328 int i;
329 u8 readkey[4];
330 readkey[0] = index >> 24;
331 readkey[1] = index >> 16;
332 readkey[2] = index >> 8;
333 readkey[3] = index;
334
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700335 if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700336 return -EIO;
337
338 for (i = 0; i < 4; i++) {
339 outb(readkey[i], APPLESMC_DATA_PORT);
340 if (__wait_status(0x04))
341 return -EIO;
342 }
343
344 outb(4, APPLESMC_DATA_PORT);
345
346 for (i = 0; i < 4; i++) {
347 if (__wait_status(0x05))
348 return -EIO;
349 key[i] = inb(APPLESMC_DATA_PORT);
350 }
351 key[4] = 0;
352
353 return 0;
354}
355
356/*
357 * applesmc_get_key_type - get key type, and put the result in type (char[6]).
358 * Returns zero on success or a negative error on failure. Callers must
359 * hold applesmc_lock.
360 */
361static int applesmc_get_key_type(char* key, char* type)
362{
363 int i;
364
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700365 if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700366 return -EIO;
367
368 for (i = 0; i < 4; i++) {
369 outb(key[i], APPLESMC_DATA_PORT);
370 if (__wait_status(0x04))
371 return -EIO;
372 }
373
Henrik Rydberg05224092008-10-18 20:27:35 -0700374 outb(6, APPLESMC_DATA_PORT);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700375
376 for (i = 0; i < 6; i++) {
377 if (__wait_status(0x05))
378 return -EIO;
379 type[i] = inb(APPLESMC_DATA_PORT);
380 }
381 type[5] = 0;
382
383 return 0;
384}
385
386/*
387 * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
388 * hold applesmc_lock.
389 */
390static int applesmc_read_motion_sensor(int index, s16* value)
391{
392 u8 buffer[2];
393 int ret;
394
395 switch (index) {
396 case SENSOR_X:
397 ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
398 break;
399 case SENSOR_Y:
400 ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
401 break;
402 case SENSOR_Z:
403 ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
404 break;
405 default:
406 ret = -EINVAL;
407 }
408
409 *value = ((s16)buffer[0] << 8) | buffer[1];
410
411 return ret;
412}
413
414/*
415 * applesmc_device_init - initialize the accelerometer. Returns zero on success
416 * and negative error code on failure. Can sleep.
417 */
418static int applesmc_device_init(void)
419{
420 int total, ret = -ENXIO;
421 u8 buffer[2];
422
423 if (!applesmc_accelerometer)
424 return 0;
425
426 mutex_lock(&applesmc_lock);
427
428 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
429 if (debug)
430 printk(KERN_DEBUG "applesmc try %d\n", total);
431 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
432 (buffer[0] != 0x00 || buffer[1] != 0x00)) {
433 if (total == INIT_TIMEOUT_MSECS) {
434 printk(KERN_DEBUG "applesmc: device has"
435 " already been initialized"
436 " (0x%02x, 0x%02x).\n",
437 buffer[0], buffer[1]);
438 } else {
439 printk(KERN_DEBUG "applesmc: device"
440 " successfully initialized"
441 " (0x%02x, 0x%02x).\n",
442 buffer[0], buffer[1]);
443 }
444 ret = 0;
445 goto out;
446 }
447 buffer[0] = 0xe0;
448 buffer[1] = 0x00;
449 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
450 msleep(INIT_WAIT_MSECS);
451 }
452
453 printk(KERN_WARNING "applesmc: failed to init the device\n");
454
455out:
456 mutex_unlock(&applesmc_lock);
457 return ret;
458}
459
460/*
461 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
462 * applesmc_lock.
463 */
464static int applesmc_get_fan_count(void)
465{
466 int ret;
467 u8 buffer[1];
468
469 mutex_lock(&applesmc_lock);
470
471 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
472
473 mutex_unlock(&applesmc_lock);
474 if (ret)
475 return ret;
476 else
477 return buffer[0];
478}
479
480/* Device model stuff */
481static int applesmc_probe(struct platform_device *dev)
482{
483 int ret;
484
485 ret = applesmc_device_init();
486 if (ret)
487 return ret;
488
489 printk(KERN_INFO "applesmc: device successfully initialized.\n");
490 return 0;
491}
492
493static int applesmc_resume(struct platform_device *dev)
494{
495 return applesmc_device_init();
496}
497
498static struct platform_driver applesmc_driver = {
499 .probe = applesmc_probe,
500 .resume = applesmc_resume,
501 .driver = {
502 .name = "applesmc",
503 .owner = THIS_MODULE,
504 },
505};
506
507/*
508 * applesmc_calibrate - Set our "resting" values. Callers must
509 * hold applesmc_lock.
510 */
511static void applesmc_calibrate(void)
512{
513 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
514 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
515 rest_x = -rest_x;
516}
517
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400518static void applesmc_idev_poll(struct input_polled_dev *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700519{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400520 struct input_dev *idev = dev->input;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700521 s16 x, y;
522
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400523 mutex_lock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700524
525 if (applesmc_read_motion_sensor(SENSOR_X, &x))
526 goto out;
527 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
528 goto out;
529
530 x = -x;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400531 input_report_abs(idev, ABS_X, x - rest_x);
532 input_report_abs(idev, ABS_Y, y - rest_y);
533 input_sync(idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700534
535out:
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700536 mutex_unlock(&applesmc_lock);
537}
538
539/* Sysfs Files */
540
Nicolas Boichatfa744192007-05-23 13:58:13 -0700541static ssize_t applesmc_name_show(struct device *dev,
542 struct device_attribute *attr, char *buf)
543{
544 return snprintf(buf, PAGE_SIZE, "applesmc\n");
545}
546
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700547static ssize_t applesmc_position_show(struct device *dev,
548 struct device_attribute *attr, char *buf)
549{
550 int ret;
551 s16 x, y, z;
552
553 mutex_lock(&applesmc_lock);
554
555 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
556 if (ret)
557 goto out;
558 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
559 if (ret)
560 goto out;
561 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
562 if (ret)
563 goto out;
564
565out:
566 mutex_unlock(&applesmc_lock);
567 if (ret)
568 return ret;
569 else
570 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
571}
572
573static ssize_t applesmc_light_show(struct device *dev,
574 struct device_attribute *attr, char *sysfsbuf)
575{
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700576 static int data_length;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700577 int ret;
578 u8 left = 0, right = 0;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700579 u8 buffer[10], query[6];
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700580
581 mutex_lock(&applesmc_lock);
582
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700583 if (!data_length) {
584 ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
585 if (ret)
586 goto out;
587 data_length = clamp_val(query[0], 0, 10);
588 printk(KERN_INFO "applesmc: light sensor data length set to "
589 "%d\n", data_length);
590 }
591
592 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Alex Murrayc3d63622009-01-15 13:51:08 -0800593 /* newer macbooks report a single 10-bit bigendian value */
594 if (data_length == 10) {
595 left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
596 goto out;
597 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700598 left = buffer[2];
599 if (ret)
600 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700601 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700602 right = buffer[2];
603
604out:
605 mutex_unlock(&applesmc_lock);
606 if (ret)
607 return ret;
608 else
609 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
610}
611
612/* Displays degree Celsius * 1000 */
613static ssize_t applesmc_show_temperature(struct device *dev,
614 struct device_attribute *devattr, char *sysfsbuf)
615{
616 int ret;
617 u8 buffer[2];
618 unsigned int temp;
619 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
620 const char* key =
621 temperature_sensors_sets[applesmc_temperature_set][attr->index];
622
623 mutex_lock(&applesmc_lock);
624
625 ret = applesmc_read_key(key, buffer, 2);
626 temp = buffer[0]*1000;
627 temp += (buffer[1] >> 6) * 250;
628
629 mutex_unlock(&applesmc_lock);
630
631 if (ret)
632 return ret;
633 else
634 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
635}
636
637static ssize_t applesmc_show_fan_speed(struct device *dev,
638 struct device_attribute *attr, char *sysfsbuf)
639{
640 int ret;
641 unsigned int speed = 0;
642 char newkey[5];
643 u8 buffer[2];
644 struct sensor_device_attribute_2 *sensor_attr =
645 to_sensor_dev_attr_2(attr);
646
647 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
648 newkey[1] = '0' + sensor_attr->index;
649 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
650 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
651 newkey[4] = 0;
652
653 mutex_lock(&applesmc_lock);
654
655 ret = applesmc_read_key(newkey, buffer, 2);
656 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
657
658 mutex_unlock(&applesmc_lock);
659 if (ret)
660 return ret;
661 else
662 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
663}
664
665static ssize_t applesmc_store_fan_speed(struct device *dev,
666 struct device_attribute *attr,
667 const char *sysfsbuf, size_t count)
668{
669 int ret;
670 u32 speed;
671 char newkey[5];
672 u8 buffer[2];
673 struct sensor_device_attribute_2 *sensor_attr =
674 to_sensor_dev_attr_2(attr);
675
676 speed = simple_strtoul(sysfsbuf, NULL, 10);
677
678 if (speed > 0x4000) /* Bigger than a 14-bit value */
679 return -EINVAL;
680
681 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
682 newkey[1] = '0' + sensor_attr->index;
683 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
684 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
685 newkey[4] = 0;
686
687 mutex_lock(&applesmc_lock);
688
689 buffer[0] = (speed >> 6) & 0xff;
690 buffer[1] = (speed << 2) & 0xff;
691 ret = applesmc_write_key(newkey, buffer, 2);
692
693 mutex_unlock(&applesmc_lock);
694 if (ret)
695 return ret;
696 else
697 return count;
698}
699
700static ssize_t applesmc_show_fan_manual(struct device *dev,
701 struct device_attribute *devattr, char *sysfsbuf)
702{
703 int ret;
704 u16 manual = 0;
705 u8 buffer[2];
706 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
707
708 mutex_lock(&applesmc_lock);
709
710 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
711 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
712
713 mutex_unlock(&applesmc_lock);
714 if (ret)
715 return ret;
716 else
717 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
718}
719
720static ssize_t applesmc_store_fan_manual(struct device *dev,
721 struct device_attribute *devattr,
722 const char *sysfsbuf, size_t count)
723{
724 int ret;
725 u8 buffer[2];
726 u32 input;
727 u16 val;
728 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
729
730 input = simple_strtoul(sysfsbuf, NULL, 10);
731
732 mutex_lock(&applesmc_lock);
733
734 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
735 val = (buffer[0] << 8 | buffer[1]);
736 if (ret)
737 goto out;
738
739 if (input)
740 val = val | (0x01 << attr->index);
741 else
742 val = val & ~(0x01 << attr->index);
743
744 buffer[0] = (val >> 8) & 0xFF;
745 buffer[1] = val & 0xFF;
746
747 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
748
749out:
750 mutex_unlock(&applesmc_lock);
751 if (ret)
752 return ret;
753 else
754 return count;
755}
756
757static ssize_t applesmc_show_fan_position(struct device *dev,
758 struct device_attribute *attr, char *sysfsbuf)
759{
760 int ret;
761 char newkey[5];
762 u8 buffer[17];
763 struct sensor_device_attribute_2 *sensor_attr =
764 to_sensor_dev_attr_2(attr);
765
766 newkey[0] = FAN_POSITION[0];
767 newkey[1] = '0' + sensor_attr->index;
768 newkey[2] = FAN_POSITION[2];
769 newkey[3] = FAN_POSITION[3];
770 newkey[4] = 0;
771
772 mutex_lock(&applesmc_lock);
773
774 ret = applesmc_read_key(newkey, buffer, 16);
775 buffer[16] = 0;
776
777 mutex_unlock(&applesmc_lock);
778 if (ret)
779 return ret;
780 else
781 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
782}
783
784static ssize_t applesmc_calibrate_show(struct device *dev,
785 struct device_attribute *attr, char *sysfsbuf)
786{
787 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
788}
789
790static ssize_t applesmc_calibrate_store(struct device *dev,
791 struct device_attribute *attr, const char *sysfsbuf, size_t count)
792{
793 mutex_lock(&applesmc_lock);
794 applesmc_calibrate();
795 mutex_unlock(&applesmc_lock);
796
797 return count;
798}
799
800/* Store the next backlight value to be written by the work */
801static unsigned int backlight_value;
802
803static void applesmc_backlight_set(struct work_struct *work)
804{
805 u8 buffer[2];
806
807 mutex_lock(&applesmc_lock);
808 buffer[0] = backlight_value;
809 buffer[1] = 0x00;
810 applesmc_write_key(BACKLIGHT_KEY, buffer, 2);
811 mutex_unlock(&applesmc_lock);
812}
813static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
814
815static void applesmc_brightness_set(struct led_classdev *led_cdev,
816 enum led_brightness value)
817{
818 int ret;
819
820 backlight_value = value;
821 ret = queue_work(applesmc_led_wq, &backlight_work);
822
823 if (debug && (!ret))
824 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
825}
826
827static ssize_t applesmc_key_count_show(struct device *dev,
828 struct device_attribute *attr, char *sysfsbuf)
829{
830 int ret;
831 u8 buffer[4];
832 u32 count;
833
834 mutex_lock(&applesmc_lock);
835
836 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
837 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
838 ((u32)buffer[2]<<8) + buffer[3];
839
840 mutex_unlock(&applesmc_lock);
841 if (ret)
842 return ret;
843 else
844 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
845}
846
847static ssize_t applesmc_key_at_index_read_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 if (ret) {
867 mutex_unlock(&applesmc_lock);
868
869 return ret;
870 }
871
872 /*
873 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
874 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
875 */
876 ret = applesmc_read_key(key, sysfsbuf, info[0]);
877
878 mutex_unlock(&applesmc_lock);
879
880 if (!ret) {
881 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400882 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700883 return ret;
884 }
885}
886
887static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
888 struct device_attribute *attr, char *sysfsbuf)
889{
890 char key[5];
891 char info[6];
892 int ret;
893
894 mutex_lock(&applesmc_lock);
895
896 ret = applesmc_get_key_at_index(key_at_index, key);
897
898 if (ret || !key[0]) {
899 mutex_unlock(&applesmc_lock);
900
901 return -EINVAL;
902 }
903
904 ret = applesmc_get_key_type(key, info);
905
906 mutex_unlock(&applesmc_lock);
907
908 if (!ret)
909 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
910 else
911 return ret;
912}
913
914static ssize_t applesmc_key_at_index_type_show(struct device *dev,
915 struct device_attribute *attr, char *sysfsbuf)
916{
917 char key[5];
918 char info[6];
919 int ret;
920
921 mutex_lock(&applesmc_lock);
922
923 ret = applesmc_get_key_at_index(key_at_index, key);
924
925 if (ret || !key[0]) {
926 mutex_unlock(&applesmc_lock);
927
928 return -EINVAL;
929 }
930
931 ret = applesmc_get_key_type(key, info);
932
933 mutex_unlock(&applesmc_lock);
934
935 if (!ret)
936 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
937 else
938 return ret;
939}
940
941static ssize_t applesmc_key_at_index_name_show(struct device *dev,
942 struct device_attribute *attr, char *sysfsbuf)
943{
944 char key[5];
945 int ret;
946
947 mutex_lock(&applesmc_lock);
948
949 ret = applesmc_get_key_at_index(key_at_index, key);
950
951 mutex_unlock(&applesmc_lock);
952
953 if (!ret && key[0])
954 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
955 else
956 return -EINVAL;
957}
958
959static ssize_t applesmc_key_at_index_show(struct device *dev,
960 struct device_attribute *attr, char *sysfsbuf)
961{
962 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
963}
964
965static ssize_t applesmc_key_at_index_store(struct device *dev,
966 struct device_attribute *attr, const char *sysfsbuf, size_t count)
967{
968 mutex_lock(&applesmc_lock);
969
970 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
971
972 mutex_unlock(&applesmc_lock);
973
974 return count;
975}
976
977static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +0100978 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700979 .default_trigger = "nand-disk",
980 .brightness_set = applesmc_brightness_set,
981};
982
Nicolas Boichatfa744192007-05-23 13:58:13 -0700983static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
984
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700985static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
986static DEVICE_ATTR(calibrate, 0644,
987 applesmc_calibrate_show, applesmc_calibrate_store);
988
989static struct attribute *accelerometer_attributes[] = {
990 &dev_attr_position.attr,
991 &dev_attr_calibrate.attr,
992 NULL
993};
994
995static const struct attribute_group accelerometer_attributes_group =
996 { .attrs = accelerometer_attributes };
997
998static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
999
1000static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
1001static DEVICE_ATTR(key_at_index, 0644,
1002 applesmc_key_at_index_show, applesmc_key_at_index_store);
1003static DEVICE_ATTR(key_at_index_name, 0444,
1004 applesmc_key_at_index_name_show, NULL);
1005static DEVICE_ATTR(key_at_index_type, 0444,
1006 applesmc_key_at_index_type_show, NULL);
1007static DEVICE_ATTR(key_at_index_data_length, 0444,
1008 applesmc_key_at_index_data_length_show, NULL);
1009static DEVICE_ATTR(key_at_index_data, 0444,
1010 applesmc_key_at_index_read_show, NULL);
1011
1012static struct attribute *key_enumeration_attributes[] = {
1013 &dev_attr_key_count.attr,
1014 &dev_attr_key_at_index.attr,
1015 &dev_attr_key_at_index_name.attr,
1016 &dev_attr_key_at_index_type.attr,
1017 &dev_attr_key_at_index_data_length.attr,
1018 &dev_attr_key_at_index_data.attr,
1019 NULL
1020};
1021
1022static const struct attribute_group key_enumeration_group =
1023 { .attrs = key_enumeration_attributes };
1024
1025/*
1026 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1027 * - show actual speed
1028 * - show/store minimum speed
1029 * - show maximum speed
1030 * - show safe speed
1031 * - show/store target speed
1032 * - show/store manual mode
1033 */
1034#define sysfs_fan_speeds_offset(offset) \
1035static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1036 applesmc_show_fan_speed, NULL, 0, offset-1); \
1037\
1038static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1039 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1040\
1041static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1042 applesmc_show_fan_speed, NULL, 2, offset-1); \
1043\
1044static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1045 applesmc_show_fan_speed, NULL, 3, offset-1); \
1046\
1047static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1048 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1049\
1050static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1051 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1052\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001053static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001054 applesmc_show_fan_position, NULL, offset-1); \
1055\
1056static struct attribute *fan##offset##_attributes[] = { \
1057 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1058 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1059 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1060 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1061 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1062 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001063 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001064 NULL \
1065};
1066
1067/*
1068 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001069 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001070 */
1071sysfs_fan_speeds_offset(1);
1072sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001073sysfs_fan_speeds_offset(3);
1074sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001075
1076static const struct attribute_group fan_attribute_groups[] = {
1077 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001078 { .attrs = fan2_attributes },
1079 { .attrs = fan3_attributes },
1080 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001081};
1082
1083/*
1084 * Temperature sensors sysfs entries.
1085 */
1086static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1087 applesmc_show_temperature, NULL, 0);
1088static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1089 applesmc_show_temperature, NULL, 1);
1090static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1091 applesmc_show_temperature, NULL, 2);
1092static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1093 applesmc_show_temperature, NULL, 3);
1094static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1095 applesmc_show_temperature, NULL, 4);
1096static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1097 applesmc_show_temperature, NULL, 5);
1098static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1099 applesmc_show_temperature, NULL, 6);
1100static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1101 applesmc_show_temperature, NULL, 7);
1102static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1103 applesmc_show_temperature, NULL, 8);
1104static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1105 applesmc_show_temperature, NULL, 9);
1106static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1107 applesmc_show_temperature, NULL, 10);
1108static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1109 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001110static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1111 applesmc_show_temperature, NULL, 12);
1112static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1113 applesmc_show_temperature, NULL, 13);
1114static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1115 applesmc_show_temperature, NULL, 14);
1116static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1117 applesmc_show_temperature, NULL, 15);
1118static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1119 applesmc_show_temperature, NULL, 16);
1120static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1121 applesmc_show_temperature, NULL, 17);
1122static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1123 applesmc_show_temperature, NULL, 18);
1124static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1125 applesmc_show_temperature, NULL, 19);
1126static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1127 applesmc_show_temperature, NULL, 20);
1128static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1129 applesmc_show_temperature, NULL, 21);
1130static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1131 applesmc_show_temperature, NULL, 22);
1132static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1133 applesmc_show_temperature, NULL, 23);
1134static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1135 applesmc_show_temperature, NULL, 24);
1136static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1137 applesmc_show_temperature, NULL, 25);
1138static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1139 applesmc_show_temperature, NULL, 26);
1140static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1141 applesmc_show_temperature, NULL, 27);
1142static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1143 applesmc_show_temperature, NULL, 28);
1144static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1145 applesmc_show_temperature, NULL, 29);
1146static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1147 applesmc_show_temperature, NULL, 30);
1148static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1149 applesmc_show_temperature, NULL, 31);
1150static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1151 applesmc_show_temperature, NULL, 32);
1152static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1153 applesmc_show_temperature, NULL, 33);
1154static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1155 applesmc_show_temperature, NULL, 34);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001156
1157static struct attribute *temperature_attributes[] = {
1158 &sensor_dev_attr_temp1_input.dev_attr.attr,
1159 &sensor_dev_attr_temp2_input.dev_attr.attr,
1160 &sensor_dev_attr_temp3_input.dev_attr.attr,
1161 &sensor_dev_attr_temp4_input.dev_attr.attr,
1162 &sensor_dev_attr_temp5_input.dev_attr.attr,
1163 &sensor_dev_attr_temp6_input.dev_attr.attr,
1164 &sensor_dev_attr_temp7_input.dev_attr.attr,
1165 &sensor_dev_attr_temp8_input.dev_attr.attr,
1166 &sensor_dev_attr_temp9_input.dev_attr.attr,
1167 &sensor_dev_attr_temp10_input.dev_attr.attr,
1168 &sensor_dev_attr_temp11_input.dev_attr.attr,
1169 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001170 &sensor_dev_attr_temp13_input.dev_attr.attr,
1171 &sensor_dev_attr_temp14_input.dev_attr.attr,
1172 &sensor_dev_attr_temp15_input.dev_attr.attr,
1173 &sensor_dev_attr_temp16_input.dev_attr.attr,
1174 &sensor_dev_attr_temp17_input.dev_attr.attr,
1175 &sensor_dev_attr_temp18_input.dev_attr.attr,
1176 &sensor_dev_attr_temp19_input.dev_attr.attr,
1177 &sensor_dev_attr_temp20_input.dev_attr.attr,
1178 &sensor_dev_attr_temp21_input.dev_attr.attr,
1179 &sensor_dev_attr_temp22_input.dev_attr.attr,
1180 &sensor_dev_attr_temp23_input.dev_attr.attr,
1181 &sensor_dev_attr_temp24_input.dev_attr.attr,
1182 &sensor_dev_attr_temp25_input.dev_attr.attr,
1183 &sensor_dev_attr_temp26_input.dev_attr.attr,
1184 &sensor_dev_attr_temp27_input.dev_attr.attr,
1185 &sensor_dev_attr_temp28_input.dev_attr.attr,
1186 &sensor_dev_attr_temp29_input.dev_attr.attr,
1187 &sensor_dev_attr_temp30_input.dev_attr.attr,
1188 &sensor_dev_attr_temp31_input.dev_attr.attr,
1189 &sensor_dev_attr_temp32_input.dev_attr.attr,
1190 &sensor_dev_attr_temp33_input.dev_attr.attr,
1191 &sensor_dev_attr_temp34_input.dev_attr.attr,
1192 &sensor_dev_attr_temp35_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001193 NULL
1194};
1195
1196static const struct attribute_group temperature_attributes_group =
1197 { .attrs = temperature_attributes };
1198
1199/* Module stuff */
1200
1201/*
1202 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1203 */
Jeff Garzik18552562007-10-03 15:15:40 -04001204static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001205{
1206 int i = 0;
1207 struct dmi_match_data* dmi_data = id->driver_data;
1208 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1209 applesmc_accelerometer = dmi_data->accelerometer;
1210 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1211 applesmc_accelerometer ? "with" : "without");
1212 applesmc_light = dmi_data->light;
1213 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1214 applesmc_light ? "with" : "without");
1215
1216 applesmc_temperature_set = dmi_data->temperature_set;
1217 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1218 i++;
1219 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1220 return 1;
1221}
1222
1223/* Create accelerometer ressources */
1224static int applesmc_create_accelerometer(void)
1225{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001226 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001227 int ret;
1228
1229 ret = sysfs_create_group(&pdev->dev.kobj,
1230 &accelerometer_attributes_group);
1231 if (ret)
1232 goto out;
1233
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001234 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001235 if (!applesmc_idev) {
1236 ret = -ENOMEM;
1237 goto out_sysfs;
1238 }
1239
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001240 applesmc_idev->poll = applesmc_idev_poll;
1241 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1242
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001243 /* initial calibrate for the input device */
1244 applesmc_calibrate();
1245
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001246 /* initialize the input device */
1247 idev = applesmc_idev->input;
1248 idev->name = "applesmc";
1249 idev->id.bustype = BUS_HOST;
1250 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001251 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001252 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001253 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001254 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001255 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1256
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001257 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001258 if (ret)
1259 goto out_idev;
1260
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001261 return 0;
1262
1263out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001264 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001265
1266out_sysfs:
1267 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1268
1269out:
1270 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1271 return ret;
1272}
1273
1274/* Release all ressources used by the accelerometer */
1275static void applesmc_release_accelerometer(void)
1276{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001277 input_unregister_polled_device(applesmc_idev);
1278 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001279 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1280}
1281
1282static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1283/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1284 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001285/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001286 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001287/* MacBook: accelerometer and temperature set 2 */
1288 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1289/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001290 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001291/* MacPro: temperature set 4 */
1292 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001293/* iMac: temperature set 5 */
1294 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Henrik Rydberg468cc032008-11-12 13:24:58 -08001295/* MacBook3, MacBook4: accelerometer and temperature set 6 */
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001296 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001297/* MacBook Air: accelerometer, backlight and temperature set 7 */
1298 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001299/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1300 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001301/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1302 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001303/* iMac 5: light sensor only, temperature set 10 */
1304 { .accelerometer = 0, .light = 0, .temperature_set = 10 },
Henrik Rydberg181209a12008-11-06 12:53:20 -08001305/* MacBook 5: accelerometer, backlight and temperature set 11 */
1306 { .accelerometer = 1, .light = 1, .temperature_set = 11 },
Henrik Rydberga6660322008-11-06 12:53:21 -08001307/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
1308 { .accelerometer = 1, .light = 1, .temperature_set = 12 },
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001309/* iMac 8: light sensor only, temperature set 13 */
1310 { .accelerometer = 0, .light = 0, .temperature_set = 13 },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001311/* iMac 6: light sensor only, temperature set 14 */
1312 { .accelerometer = 0, .light = 0, .temperature_set = 14 },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001313/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
1314 { .accelerometer = 1, .light = 1, .temperature_set = 15 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001315};
1316
1317/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1318 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1319static __initdata struct dmi_system_id applesmc_whitelist[] = {
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001320 { applesmc_dmi_match, "Apple MacBook Air 2", {
1321 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1322 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
1323 &applesmc_dmi_data[15]},
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001324 { applesmc_dmi_match, "Apple MacBook Air", {
1325 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1326 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001327 &applesmc_dmi_data[7]},
Henrik Rydberga6660322008-11-06 12:53:21 -08001328 { applesmc_dmi_match, "Apple MacBook Pro 5", {
1329 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1330 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
1331 &applesmc_dmi_data[12]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001332 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1333 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1334 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1335 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001336 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1337 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1338 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1339 &applesmc_dmi_data[9]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001340 { applesmc_dmi_match, "Apple MacBook Pro", {
1341 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1342 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001343 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001344 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001345 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001346 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001347 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001348 { applesmc_dmi_match, "Apple MacBook (v3)", {
1349 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1350 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001351 &applesmc_dmi_data[6]},
Henrik Rydberg468cc032008-11-12 13:24:58 -08001352 { applesmc_dmi_match, "Apple MacBook 4", {
1353 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1354 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
1355 &applesmc_dmi_data[6]},
Henrik Rydberg181209a12008-11-06 12:53:20 -08001356 { applesmc_dmi_match, "Apple MacBook 5", {
1357 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1358 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
1359 &applesmc_dmi_data[11]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001360 { applesmc_dmi_match, "Apple MacBook", {
1361 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1362 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001363 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001364 { applesmc_dmi_match, "Apple Macmini", {
1365 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1366 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001367 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001368 { applesmc_dmi_match, "Apple MacPro2", {
1369 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1370 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001371 &applesmc_dmi_data[4]},
Henrik Rydberg45a3a362008-11-19 15:36:42 -08001372 { applesmc_dmi_match, "Apple MacPro", {
1373 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1374 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1375 &applesmc_dmi_data[4]},
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001376 { applesmc_dmi_match, "Apple iMac 8", {
1377 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1378 DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
1379 &applesmc_dmi_data[13]},
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001380 { applesmc_dmi_match, "Apple iMac 6", {
1381 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1382 DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
1383 &applesmc_dmi_data[14]},
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001384 { applesmc_dmi_match, "Apple iMac 5", {
1385 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1386 DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
1387 &applesmc_dmi_data[10]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001388 { applesmc_dmi_match, "Apple iMac", {
1389 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1390 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001391 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001392 { .ident = NULL }
1393};
1394
1395static int __init applesmc_init(void)
1396{
1397 int ret;
1398 int count;
1399 int i;
1400
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001401 if (!dmi_check_system(applesmc_whitelist)) {
1402 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1403 ret = -ENODEV;
1404 goto out;
1405 }
1406
1407 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1408 "applesmc")) {
1409 ret = -ENXIO;
1410 goto out;
1411 }
1412
1413 ret = platform_driver_register(&applesmc_driver);
1414 if (ret)
1415 goto out_region;
1416
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001417 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1418 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001419 if (IS_ERR(pdev)) {
1420 ret = PTR_ERR(pdev);
1421 goto out_driver;
1422 }
1423
Nicolas Boichatfa744192007-05-23 13:58:13 -07001424 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001425 if (ret)
1426 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001427
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001428 /* Create key enumeration sysfs files */
1429 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1430 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001431 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001432
1433 /* create fan files */
1434 count = applesmc_get_fan_count();
1435 if (count < 0) {
1436 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
1437 } else {
1438 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1439
1440 switch (count) {
1441 default:
René Rebe8de57702007-10-16 14:19:20 -07001442 printk(KERN_WARNING "applesmc: More than 4 fans found,"
1443 " but at most 4 fans are supported"
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001444 " by the driver.\n");
René Rebe8de57702007-10-16 14:19:20 -07001445 case 4:
1446 ret = sysfs_create_group(&pdev->dev.kobj,
1447 &fan_attribute_groups[3]);
1448 if (ret)
1449 goto out_key_enumeration;
1450 case 3:
1451 ret = sysfs_create_group(&pdev->dev.kobj,
1452 &fan_attribute_groups[2]);
1453 if (ret)
1454 goto out_key_enumeration;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001455 case 2:
1456 ret = sysfs_create_group(&pdev->dev.kobj,
1457 &fan_attribute_groups[1]);
1458 if (ret)
1459 goto out_key_enumeration;
1460 case 1:
1461 ret = sysfs_create_group(&pdev->dev.kobj,
1462 &fan_attribute_groups[0]);
1463 if (ret)
1464 goto out_fan_1;
1465 case 0:
1466 ;
1467 }
1468 }
1469
1470 for (i = 0;
1471 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1472 i++) {
1473 if (temperature_attributes[i] == NULL) {
1474 printk(KERN_ERR "applesmc: More temperature sensors "
1475 "in temperature_sensors_sets (at least %i)"
1476 "than available sysfs files in "
1477 "temperature_attributes (%i), please report "
1478 "this bug.\n", i, i-1);
1479 goto out_temperature;
1480 }
1481 ret = sysfs_create_file(&pdev->dev.kobj,
1482 temperature_attributes[i]);
1483 if (ret)
1484 goto out_temperature;
1485 }
1486
1487 if (applesmc_accelerometer) {
1488 ret = applesmc_create_accelerometer();
1489 if (ret)
1490 goto out_temperature;
1491 }
1492
1493 if (applesmc_light) {
1494 /* Add light sensor file */
1495 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1496 if (ret)
1497 goto out_accelerometer;
1498
1499 /* Create the workqueue */
1500 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1501 if (!applesmc_led_wq) {
1502 ret = -ENOMEM;
1503 goto out_light_sysfs;
1504 }
1505
1506 /* register as a led device */
1507 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1508 if (ret < 0)
1509 goto out_light_wq;
1510 }
1511
Tony Jones1beeffe2007-08-20 13:46:20 -07001512 hwmon_dev = hwmon_device_register(&pdev->dev);
1513 if (IS_ERR(hwmon_dev)) {
1514 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001515 goto out_light_ledclass;
1516 }
1517
1518 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1519
1520 return 0;
1521
1522out_light_ledclass:
1523 if (applesmc_light)
1524 led_classdev_unregister(&applesmc_backlight);
1525out_light_wq:
1526 if (applesmc_light)
1527 destroy_workqueue(applesmc_led_wq);
1528out_light_sysfs:
1529 if (applesmc_light)
1530 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1531out_accelerometer:
1532 if (applesmc_accelerometer)
1533 applesmc_release_accelerometer();
1534out_temperature:
1535 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1536 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1537out_fan_1:
1538 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1539out_key_enumeration:
1540 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001541out_name:
1542 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001543out_device:
1544 platform_device_unregister(pdev);
1545out_driver:
1546 platform_driver_unregister(&applesmc_driver);
1547out_region:
1548 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1549out:
1550 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1551 return ret;
1552}
1553
1554static void __exit applesmc_exit(void)
1555{
Tony Jones1beeffe2007-08-20 13:46:20 -07001556 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001557 if (applesmc_light) {
1558 led_classdev_unregister(&applesmc_backlight);
1559 destroy_workqueue(applesmc_led_wq);
1560 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1561 }
1562 if (applesmc_accelerometer)
1563 applesmc_release_accelerometer();
1564 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1565 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1566 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1567 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001568 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001569 platform_device_unregister(pdev);
1570 platform_driver_unregister(&applesmc_driver);
1571 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1572
1573 printk(KERN_INFO "applesmc: driver unloaded.\n");
1574}
1575
1576module_init(applesmc_init);
1577module_exit(applesmc_exit);
1578
1579MODULE_AUTHOR("Nicolas Boichat");
1580MODULE_DESCRIPTION("Apple SMC");
1581MODULE_LICENSE("GPL v2");
Henrik Rydbergdc924ef2008-12-01 13:13:49 -08001582MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);