blob: 0f28d91f29d8ef81c50b036bad0c84ca78e76bd8 [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>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020038#include <linux/io.h>
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070039#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 */
Bharath Rameshfb9f88e2009-01-29 14:25:24 -080086static const char *temperature_sensors_sets[][41] = {
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 },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -0800138/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */
139 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
140 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P",
141 "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P",
142 "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S",
143 "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S",
144 NULL },
Justin P. Mattocke1741712010-04-14 16:14:10 +0200145/* Set 17: iMac 9,1 */
146 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TH0P", "TL0P",
147 "TN0D", "TN0H", "TN0P", "TO0P", "Tm0P", "Tp0P", NULL },
148/* Set 18: MacBook Pro 2,2 */
149 { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
150 "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700151};
152
153/* List of keys used to read/write fan speeds */
154static const char* fan_speed_keys[] = {
155 FAN_ACTUAL_SPEED,
156 FAN_MIN_SPEED,
157 FAN_MAX_SPEED,
158 FAN_SAFE_SPEED,
159 FAN_TARGET_SPEED
160};
161
162#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
163#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
164
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400165#define APPLESMC_POLL_INTERVAL 50 /* msecs */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700166#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
167#define APPLESMC_INPUT_FLAT 4
168
169#define SENSOR_X 0
170#define SENSOR_Y 1
171#define SENSOR_Z 2
172
173/* Structure to be passed to DMI_MATCH function */
174struct dmi_match_data {
175/* Indicates whether this computer has an accelerometer. */
176 int accelerometer;
177/* Indicates whether this computer has light sensors and keyboard backlight. */
178 int light;
179/* Indicates which temperature sensors set to use. */
180 int temperature_set;
181};
182
183static const int debug;
184static struct platform_device *pdev;
185static s16 rest_x;
186static s16 rest_y;
Henrik Rydberga976f152009-09-21 17:04:50 -0700187static u8 backlight_state[2];
188
Tony Jones1beeffe2007-08-20 13:46:20 -0700189static struct device *hwmon_dev;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400190static struct input_polled_dev *applesmc_idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700191
192/* Indicates whether this computer has an accelerometer. */
193static unsigned int applesmc_accelerometer;
194
195/* Indicates whether this computer has light sensors and keyboard backlight. */
196static unsigned int applesmc_light;
197
198/* Indicates which temperature sensors set to use. */
199static unsigned int applesmc_temperature_set;
200
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400201static DEFINE_MUTEX(applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700202
203/*
204 * Last index written to key_at_index sysfs file, and value to use for all other
205 * key_at_index_* sysfs files.
206 */
207static unsigned int key_at_index;
208
209static struct workqueue_struct *applesmc_led_wq;
210
211/*
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700212 * __wait_status - Wait up to 32ms for the status port to get a certain value
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700213 * (masked with 0x0f), returning zero if the value is obtained. Callers must
214 * hold applesmc_lock.
215 */
216static int __wait_status(u8 val)
217{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700218 int us;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700219
220 val = val & APPLESMC_STATUS_MASK;
221
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700222 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
223 udelay(us);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700224 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
225 if (debug)
226 printk(KERN_DEBUG
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700227 "Waited %d us for status %x\n",
228 2 * us - APPLESMC_MIN_WAIT, val);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700229 return 0;
230 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700231 }
232
233 printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
234 val, inb(APPLESMC_CMD_PORT));
235
236 return -EIO;
237}
238
239/*
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700240 * special treatment of command port - on newer macbooks, it seems necessary
241 * to resend the command byte before polling the status again. Callers must
242 * hold applesmc_lock.
243 */
244static int send_command(u8 cmd)
245{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700246 int us;
247 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700248 outb(cmd, APPLESMC_CMD_PORT);
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700249 udelay(us);
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700250 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
251 return 0;
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700252 }
253 printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
254 cmd, inb(APPLESMC_CMD_PORT));
255 return -EIO;
256}
257
258/*
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700259 * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
260 * Returns zero on success or a negative error on failure. Callers must
261 * hold applesmc_lock.
262 */
263static int applesmc_read_key(const char* key, u8* buffer, u8 len)
264{
265 int i;
266
267 if (len > APPLESMC_MAX_DATA_LENGTH) {
268 printk(KERN_ERR "applesmc_read_key: cannot read more than "
269 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
270 return -EINVAL;
271 }
272
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700273 if (send_command(APPLESMC_READ_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700274 return -EIO;
275
276 for (i = 0; i < 4; i++) {
277 outb(key[i], APPLESMC_DATA_PORT);
278 if (__wait_status(0x04))
279 return -EIO;
280 }
281 if (debug)
282 printk(KERN_DEBUG "<%s", key);
283
284 outb(len, APPLESMC_DATA_PORT);
285 if (debug)
286 printk(KERN_DEBUG ">%x", len);
287
288 for (i = 0; i < len; i++) {
289 if (__wait_status(0x05))
290 return -EIO;
291 buffer[i] = inb(APPLESMC_DATA_PORT);
292 if (debug)
293 printk(KERN_DEBUG "<%x", buffer[i]);
294 }
295 if (debug)
296 printk(KERN_DEBUG "\n");
297
298 return 0;
299}
300
301/*
302 * applesmc_write_key - writes len bytes from buffer to a given key.
303 * Returns zero on success or a negative error on failure. Callers must
304 * hold applesmc_lock.
305 */
306static int applesmc_write_key(const char* key, u8* buffer, u8 len)
307{
308 int i;
309
310 if (len > APPLESMC_MAX_DATA_LENGTH) {
311 printk(KERN_ERR "applesmc_write_key: cannot write more than "
312 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
313 return -EINVAL;
314 }
315
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700316 if (send_command(APPLESMC_WRITE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700317 return -EIO;
318
319 for (i = 0; i < 4; i++) {
320 outb(key[i], APPLESMC_DATA_PORT);
321 if (__wait_status(0x04))
322 return -EIO;
323 }
324
325 outb(len, APPLESMC_DATA_PORT);
326
327 for (i = 0; i < len; i++) {
328 if (__wait_status(0x04))
329 return -EIO;
330 outb(buffer[i], APPLESMC_DATA_PORT);
331 }
332
333 return 0;
334}
335
336/*
337 * applesmc_get_key_at_index - get key at index, and put the result in key
338 * (char[6]). Returns zero on success or a negative error on failure. Callers
339 * must hold applesmc_lock.
340 */
341static int applesmc_get_key_at_index(int index, char* key)
342{
343 int i;
344 u8 readkey[4];
345 readkey[0] = index >> 24;
346 readkey[1] = index >> 16;
347 readkey[2] = index >> 8;
348 readkey[3] = index;
349
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700350 if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700351 return -EIO;
352
353 for (i = 0; i < 4; i++) {
354 outb(readkey[i], APPLESMC_DATA_PORT);
355 if (__wait_status(0x04))
356 return -EIO;
357 }
358
359 outb(4, APPLESMC_DATA_PORT);
360
361 for (i = 0; i < 4; i++) {
362 if (__wait_status(0x05))
363 return -EIO;
364 key[i] = inb(APPLESMC_DATA_PORT);
365 }
366 key[4] = 0;
367
368 return 0;
369}
370
371/*
372 * applesmc_get_key_type - get key type, and put the result in type (char[6]).
373 * Returns zero on success or a negative error on failure. Callers must
374 * hold applesmc_lock.
375 */
376static int applesmc_get_key_type(char* key, char* type)
377{
378 int i;
379
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700380 if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700381 return -EIO;
382
383 for (i = 0; i < 4; i++) {
384 outb(key[i], APPLESMC_DATA_PORT);
385 if (__wait_status(0x04))
386 return -EIO;
387 }
388
Henrik Rydberg05224092008-10-18 20:27:35 -0700389 outb(6, APPLESMC_DATA_PORT);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700390
391 for (i = 0; i < 6; i++) {
392 if (__wait_status(0x05))
393 return -EIO;
394 type[i] = inb(APPLESMC_DATA_PORT);
395 }
396 type[5] = 0;
397
398 return 0;
399}
400
401/*
402 * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
403 * hold applesmc_lock.
404 */
405static int applesmc_read_motion_sensor(int index, s16* value)
406{
407 u8 buffer[2];
408 int ret;
409
410 switch (index) {
411 case SENSOR_X:
412 ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
413 break;
414 case SENSOR_Y:
415 ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
416 break;
417 case SENSOR_Z:
418 ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
419 break;
420 default:
421 ret = -EINVAL;
422 }
423
424 *value = ((s16)buffer[0] << 8) | buffer[1];
425
426 return ret;
427}
428
429/*
430 * applesmc_device_init - initialize the accelerometer. Returns zero on success
431 * and negative error code on failure. Can sleep.
432 */
433static int applesmc_device_init(void)
434{
435 int total, ret = -ENXIO;
436 u8 buffer[2];
437
438 if (!applesmc_accelerometer)
439 return 0;
440
441 mutex_lock(&applesmc_lock);
442
443 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
444 if (debug)
445 printk(KERN_DEBUG "applesmc try %d\n", total);
446 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
447 (buffer[0] != 0x00 || buffer[1] != 0x00)) {
448 if (total == INIT_TIMEOUT_MSECS) {
449 printk(KERN_DEBUG "applesmc: device has"
450 " already been initialized"
451 " (0x%02x, 0x%02x).\n",
452 buffer[0], buffer[1]);
453 } else {
454 printk(KERN_DEBUG "applesmc: device"
455 " successfully initialized"
456 " (0x%02x, 0x%02x).\n",
457 buffer[0], buffer[1]);
458 }
459 ret = 0;
460 goto out;
461 }
462 buffer[0] = 0xe0;
463 buffer[1] = 0x00;
464 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
465 msleep(INIT_WAIT_MSECS);
466 }
467
468 printk(KERN_WARNING "applesmc: failed to init the device\n");
469
470out:
471 mutex_unlock(&applesmc_lock);
472 return ret;
473}
474
475/*
476 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
477 * applesmc_lock.
478 */
479static int applesmc_get_fan_count(void)
480{
481 int ret;
482 u8 buffer[1];
483
484 mutex_lock(&applesmc_lock);
485
486 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
487
488 mutex_unlock(&applesmc_lock);
489 if (ret)
490 return ret;
491 else
492 return buffer[0];
493}
494
495/* Device model stuff */
496static int applesmc_probe(struct platform_device *dev)
497{
498 int ret;
499
500 ret = applesmc_device_init();
501 if (ret)
502 return ret;
503
504 printk(KERN_INFO "applesmc: device successfully initialized.\n");
505 return 0;
506}
507
Henrik Rydberga976f152009-09-21 17:04:50 -0700508/* Synchronize device with memorized backlight state */
509static int applesmc_pm_resume(struct device *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700510{
Henrik Rydberga976f152009-09-21 17:04:50 -0700511 mutex_lock(&applesmc_lock);
512 if (applesmc_light)
513 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
514 mutex_unlock(&applesmc_lock);
515 return 0;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700516}
517
Henrik Rydberga976f152009-09-21 17:04:50 -0700518/* Reinitialize device on resume from hibernation */
519static int applesmc_pm_restore(struct device *dev)
520{
521 int ret = applesmc_device_init();
522 if (ret)
523 return ret;
524 return applesmc_pm_resume(dev);
525}
526
Alexey Dobriyan47145212009-12-14 18:00:08 -0800527static const struct dev_pm_ops applesmc_pm_ops = {
Henrik Rydberga976f152009-09-21 17:04:50 -0700528 .resume = applesmc_pm_resume,
529 .restore = applesmc_pm_restore,
530};
531
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700532static struct platform_driver applesmc_driver = {
533 .probe = applesmc_probe,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700534 .driver = {
535 .name = "applesmc",
536 .owner = THIS_MODULE,
Henrik Rydberga976f152009-09-21 17:04:50 -0700537 .pm = &applesmc_pm_ops,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700538 },
539};
540
541/*
542 * applesmc_calibrate - Set our "resting" values. Callers must
543 * hold applesmc_lock.
544 */
545static void applesmc_calibrate(void)
546{
547 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
548 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
549 rest_x = -rest_x;
550}
551
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400552static void applesmc_idev_poll(struct input_polled_dev *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700553{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400554 struct input_dev *idev = dev->input;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700555 s16 x, y;
556
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400557 mutex_lock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700558
559 if (applesmc_read_motion_sensor(SENSOR_X, &x))
560 goto out;
561 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
562 goto out;
563
564 x = -x;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400565 input_report_abs(idev, ABS_X, x - rest_x);
566 input_report_abs(idev, ABS_Y, y - rest_y);
567 input_sync(idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700568
569out:
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700570 mutex_unlock(&applesmc_lock);
571}
572
573/* Sysfs Files */
574
Nicolas Boichatfa744192007-05-23 13:58:13 -0700575static ssize_t applesmc_name_show(struct device *dev,
576 struct device_attribute *attr, char *buf)
577{
578 return snprintf(buf, PAGE_SIZE, "applesmc\n");
579}
580
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700581static ssize_t applesmc_position_show(struct device *dev,
582 struct device_attribute *attr, char *buf)
583{
584 int ret;
585 s16 x, y, z;
586
587 mutex_lock(&applesmc_lock);
588
589 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
590 if (ret)
591 goto out;
592 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
593 if (ret)
594 goto out;
595 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
596 if (ret)
597 goto out;
598
599out:
600 mutex_unlock(&applesmc_lock);
601 if (ret)
602 return ret;
603 else
604 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
605}
606
607static ssize_t applesmc_light_show(struct device *dev,
608 struct device_attribute *attr, char *sysfsbuf)
609{
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700610 static int data_length;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700611 int ret;
612 u8 left = 0, right = 0;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700613 u8 buffer[10], query[6];
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700614
615 mutex_lock(&applesmc_lock);
616
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700617 if (!data_length) {
618 ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
619 if (ret)
620 goto out;
621 data_length = clamp_val(query[0], 0, 10);
622 printk(KERN_INFO "applesmc: light sensor data length set to "
623 "%d\n", data_length);
624 }
625
626 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Alex Murrayc3d63622009-01-15 13:51:08 -0800627 /* newer macbooks report a single 10-bit bigendian value */
628 if (data_length == 10) {
629 left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
630 goto out;
631 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700632 left = buffer[2];
633 if (ret)
634 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700635 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700636 right = buffer[2];
637
638out:
639 mutex_unlock(&applesmc_lock);
640 if (ret)
641 return ret;
642 else
643 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
644}
645
646/* Displays degree Celsius * 1000 */
647static ssize_t applesmc_show_temperature(struct device *dev,
648 struct device_attribute *devattr, char *sysfsbuf)
649{
650 int ret;
651 u8 buffer[2];
652 unsigned int temp;
653 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
654 const char* key =
655 temperature_sensors_sets[applesmc_temperature_set][attr->index];
656
657 mutex_lock(&applesmc_lock);
658
659 ret = applesmc_read_key(key, buffer, 2);
660 temp = buffer[0]*1000;
661 temp += (buffer[1] >> 6) * 250;
662
663 mutex_unlock(&applesmc_lock);
664
665 if (ret)
666 return ret;
667 else
668 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
669}
670
671static ssize_t applesmc_show_fan_speed(struct device *dev,
672 struct device_attribute *attr, char *sysfsbuf)
673{
674 int ret;
675 unsigned int speed = 0;
676 char newkey[5];
677 u8 buffer[2];
678 struct sensor_device_attribute_2 *sensor_attr =
679 to_sensor_dev_attr_2(attr);
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 ret = applesmc_read_key(newkey, buffer, 2);
690 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
691
692 mutex_unlock(&applesmc_lock);
693 if (ret)
694 return ret;
695 else
696 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
697}
698
699static ssize_t applesmc_store_fan_speed(struct device *dev,
700 struct device_attribute *attr,
701 const char *sysfsbuf, size_t count)
702{
703 int ret;
704 u32 speed;
705 char newkey[5];
706 u8 buffer[2];
707 struct sensor_device_attribute_2 *sensor_attr =
708 to_sensor_dev_attr_2(attr);
709
710 speed = simple_strtoul(sysfsbuf, NULL, 10);
711
712 if (speed > 0x4000) /* Bigger than a 14-bit value */
713 return -EINVAL;
714
715 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
716 newkey[1] = '0' + sensor_attr->index;
717 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
718 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
719 newkey[4] = 0;
720
721 mutex_lock(&applesmc_lock);
722
723 buffer[0] = (speed >> 6) & 0xff;
724 buffer[1] = (speed << 2) & 0xff;
725 ret = applesmc_write_key(newkey, buffer, 2);
726
727 mutex_unlock(&applesmc_lock);
728 if (ret)
729 return ret;
730 else
731 return count;
732}
733
734static ssize_t applesmc_show_fan_manual(struct device *dev,
735 struct device_attribute *devattr, char *sysfsbuf)
736{
737 int ret;
738 u16 manual = 0;
739 u8 buffer[2];
740 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
741
742 mutex_lock(&applesmc_lock);
743
744 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
745 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
746
747 mutex_unlock(&applesmc_lock);
748 if (ret)
749 return ret;
750 else
751 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
752}
753
754static ssize_t applesmc_store_fan_manual(struct device *dev,
755 struct device_attribute *devattr,
756 const char *sysfsbuf, size_t count)
757{
758 int ret;
759 u8 buffer[2];
760 u32 input;
761 u16 val;
762 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
763
764 input = simple_strtoul(sysfsbuf, NULL, 10);
765
766 mutex_lock(&applesmc_lock);
767
768 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
769 val = (buffer[0] << 8 | buffer[1]);
770 if (ret)
771 goto out;
772
773 if (input)
774 val = val | (0x01 << attr->index);
775 else
776 val = val & ~(0x01 << attr->index);
777
778 buffer[0] = (val >> 8) & 0xFF;
779 buffer[1] = val & 0xFF;
780
781 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
782
783out:
784 mutex_unlock(&applesmc_lock);
785 if (ret)
786 return ret;
787 else
788 return count;
789}
790
791static ssize_t applesmc_show_fan_position(struct device *dev,
792 struct device_attribute *attr, char *sysfsbuf)
793{
794 int ret;
795 char newkey[5];
796 u8 buffer[17];
797 struct sensor_device_attribute_2 *sensor_attr =
798 to_sensor_dev_attr_2(attr);
799
800 newkey[0] = FAN_POSITION[0];
801 newkey[1] = '0' + sensor_attr->index;
802 newkey[2] = FAN_POSITION[2];
803 newkey[3] = FAN_POSITION[3];
804 newkey[4] = 0;
805
806 mutex_lock(&applesmc_lock);
807
808 ret = applesmc_read_key(newkey, buffer, 16);
809 buffer[16] = 0;
810
811 mutex_unlock(&applesmc_lock);
812 if (ret)
813 return ret;
814 else
815 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
816}
817
818static ssize_t applesmc_calibrate_show(struct device *dev,
819 struct device_attribute *attr, char *sysfsbuf)
820{
821 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
822}
823
824static ssize_t applesmc_calibrate_store(struct device *dev,
825 struct device_attribute *attr, const char *sysfsbuf, size_t count)
826{
827 mutex_lock(&applesmc_lock);
828 applesmc_calibrate();
829 mutex_unlock(&applesmc_lock);
830
831 return count;
832}
833
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700834static void applesmc_backlight_set(struct work_struct *work)
835{
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700836 mutex_lock(&applesmc_lock);
Henrik Rydberga976f152009-09-21 17:04:50 -0700837 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700838 mutex_unlock(&applesmc_lock);
839}
840static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
841
842static void applesmc_brightness_set(struct led_classdev *led_cdev,
843 enum led_brightness value)
844{
845 int ret;
846
Henrik Rydberga976f152009-09-21 17:04:50 -0700847 backlight_state[0] = value;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700848 ret = queue_work(applesmc_led_wq, &backlight_work);
849
850 if (debug && (!ret))
851 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
852}
853
854static ssize_t applesmc_key_count_show(struct device *dev,
855 struct device_attribute *attr, char *sysfsbuf)
856{
857 int ret;
858 u8 buffer[4];
859 u32 count;
860
861 mutex_lock(&applesmc_lock);
862
863 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
864 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
865 ((u32)buffer[2]<<8) + buffer[3];
866
867 mutex_unlock(&applesmc_lock);
868 if (ret)
869 return ret;
870 else
871 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
872}
873
874static ssize_t applesmc_key_at_index_read_show(struct device *dev,
875 struct device_attribute *attr, char *sysfsbuf)
876{
877 char key[5];
878 char info[6];
879 int ret;
880
881 mutex_lock(&applesmc_lock);
882
883 ret = applesmc_get_key_at_index(key_at_index, key);
884
885 if (ret || !key[0]) {
886 mutex_unlock(&applesmc_lock);
887
888 return -EINVAL;
889 }
890
891 ret = applesmc_get_key_type(key, info);
892
893 if (ret) {
894 mutex_unlock(&applesmc_lock);
895
896 return ret;
897 }
898
899 /*
900 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
901 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
902 */
903 ret = applesmc_read_key(key, sysfsbuf, info[0]);
904
905 mutex_unlock(&applesmc_lock);
906
907 if (!ret) {
908 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400909 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700910 return ret;
911 }
912}
913
914static ssize_t applesmc_key_at_index_data_length_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, "%d\n", info[0]);
937 else
938 return ret;
939}
940
941static ssize_t applesmc_key_at_index_type_show(struct device *dev,
942 struct device_attribute *attr, char *sysfsbuf)
943{
944 char key[5];
945 char info[6];
946 int ret;
947
948 mutex_lock(&applesmc_lock);
949
950 ret = applesmc_get_key_at_index(key_at_index, key);
951
952 if (ret || !key[0]) {
953 mutex_unlock(&applesmc_lock);
954
955 return -EINVAL;
956 }
957
958 ret = applesmc_get_key_type(key, info);
959
960 mutex_unlock(&applesmc_lock);
961
962 if (!ret)
963 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
964 else
965 return ret;
966}
967
968static ssize_t applesmc_key_at_index_name_show(struct device *dev,
969 struct device_attribute *attr, char *sysfsbuf)
970{
971 char key[5];
972 int ret;
973
974 mutex_lock(&applesmc_lock);
975
976 ret = applesmc_get_key_at_index(key_at_index, key);
977
978 mutex_unlock(&applesmc_lock);
979
980 if (!ret && key[0])
981 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
982 else
983 return -EINVAL;
984}
985
986static ssize_t applesmc_key_at_index_show(struct device *dev,
987 struct device_attribute *attr, char *sysfsbuf)
988{
989 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
990}
991
992static ssize_t applesmc_key_at_index_store(struct device *dev,
993 struct device_attribute *attr, const char *sysfsbuf, size_t count)
994{
995 mutex_lock(&applesmc_lock);
996
997 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
998
999 mutex_unlock(&applesmc_lock);
1000
1001 return count;
1002}
1003
1004static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +01001005 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001006 .default_trigger = "nand-disk",
1007 .brightness_set = applesmc_brightness_set,
1008};
1009
Nicolas Boichatfa744192007-05-23 13:58:13 -07001010static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
1011
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001012static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
1013static DEVICE_ATTR(calibrate, 0644,
1014 applesmc_calibrate_show, applesmc_calibrate_store);
1015
1016static struct attribute *accelerometer_attributes[] = {
1017 &dev_attr_position.attr,
1018 &dev_attr_calibrate.attr,
1019 NULL
1020};
1021
1022static const struct attribute_group accelerometer_attributes_group =
1023 { .attrs = accelerometer_attributes };
1024
1025static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
1026
1027static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
1028static DEVICE_ATTR(key_at_index, 0644,
1029 applesmc_key_at_index_show, applesmc_key_at_index_store);
1030static DEVICE_ATTR(key_at_index_name, 0444,
1031 applesmc_key_at_index_name_show, NULL);
1032static DEVICE_ATTR(key_at_index_type, 0444,
1033 applesmc_key_at_index_type_show, NULL);
1034static DEVICE_ATTR(key_at_index_data_length, 0444,
1035 applesmc_key_at_index_data_length_show, NULL);
1036static DEVICE_ATTR(key_at_index_data, 0444,
1037 applesmc_key_at_index_read_show, NULL);
1038
1039static struct attribute *key_enumeration_attributes[] = {
1040 &dev_attr_key_count.attr,
1041 &dev_attr_key_at_index.attr,
1042 &dev_attr_key_at_index_name.attr,
1043 &dev_attr_key_at_index_type.attr,
1044 &dev_attr_key_at_index_data_length.attr,
1045 &dev_attr_key_at_index_data.attr,
1046 NULL
1047};
1048
1049static const struct attribute_group key_enumeration_group =
1050 { .attrs = key_enumeration_attributes };
1051
1052/*
1053 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1054 * - show actual speed
1055 * - show/store minimum speed
1056 * - show maximum speed
1057 * - show safe speed
1058 * - show/store target speed
1059 * - show/store manual mode
1060 */
1061#define sysfs_fan_speeds_offset(offset) \
1062static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1063 applesmc_show_fan_speed, NULL, 0, offset-1); \
1064\
1065static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1066 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1067\
1068static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1069 applesmc_show_fan_speed, NULL, 2, offset-1); \
1070\
1071static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1072 applesmc_show_fan_speed, NULL, 3, offset-1); \
1073\
1074static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1075 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1076\
1077static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1078 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1079\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001080static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001081 applesmc_show_fan_position, NULL, offset-1); \
1082\
1083static struct attribute *fan##offset##_attributes[] = { \
1084 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1085 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1086 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1087 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1088 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1089 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001090 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001091 NULL \
1092};
1093
1094/*
1095 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001096 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001097 */
1098sysfs_fan_speeds_offset(1);
1099sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001100sysfs_fan_speeds_offset(3);
1101sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001102
1103static const struct attribute_group fan_attribute_groups[] = {
1104 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001105 { .attrs = fan2_attributes },
1106 { .attrs = fan3_attributes },
1107 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001108};
1109
1110/*
1111 * Temperature sensors sysfs entries.
1112 */
1113static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1114 applesmc_show_temperature, NULL, 0);
1115static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1116 applesmc_show_temperature, NULL, 1);
1117static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1118 applesmc_show_temperature, NULL, 2);
1119static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1120 applesmc_show_temperature, NULL, 3);
1121static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1122 applesmc_show_temperature, NULL, 4);
1123static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1124 applesmc_show_temperature, NULL, 5);
1125static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1126 applesmc_show_temperature, NULL, 6);
1127static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1128 applesmc_show_temperature, NULL, 7);
1129static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1130 applesmc_show_temperature, NULL, 8);
1131static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1132 applesmc_show_temperature, NULL, 9);
1133static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1134 applesmc_show_temperature, NULL, 10);
1135static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1136 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001137static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1138 applesmc_show_temperature, NULL, 12);
1139static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1140 applesmc_show_temperature, NULL, 13);
1141static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1142 applesmc_show_temperature, NULL, 14);
1143static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1144 applesmc_show_temperature, NULL, 15);
1145static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1146 applesmc_show_temperature, NULL, 16);
1147static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1148 applesmc_show_temperature, NULL, 17);
1149static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1150 applesmc_show_temperature, NULL, 18);
1151static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1152 applesmc_show_temperature, NULL, 19);
1153static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1154 applesmc_show_temperature, NULL, 20);
1155static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1156 applesmc_show_temperature, NULL, 21);
1157static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1158 applesmc_show_temperature, NULL, 22);
1159static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1160 applesmc_show_temperature, NULL, 23);
1161static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1162 applesmc_show_temperature, NULL, 24);
1163static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1164 applesmc_show_temperature, NULL, 25);
1165static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1166 applesmc_show_temperature, NULL, 26);
1167static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1168 applesmc_show_temperature, NULL, 27);
1169static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1170 applesmc_show_temperature, NULL, 28);
1171static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1172 applesmc_show_temperature, NULL, 29);
1173static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1174 applesmc_show_temperature, NULL, 30);
1175static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1176 applesmc_show_temperature, NULL, 31);
1177static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1178 applesmc_show_temperature, NULL, 32);
1179static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1180 applesmc_show_temperature, NULL, 33);
1181static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1182 applesmc_show_temperature, NULL, 34);
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001183static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
1184 applesmc_show_temperature, NULL, 35);
1185static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
1186 applesmc_show_temperature, NULL, 36);
1187static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
1188 applesmc_show_temperature, NULL, 37);
1189static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
1190 applesmc_show_temperature, NULL, 38);
1191static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
1192 applesmc_show_temperature, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001193
1194static struct attribute *temperature_attributes[] = {
1195 &sensor_dev_attr_temp1_input.dev_attr.attr,
1196 &sensor_dev_attr_temp2_input.dev_attr.attr,
1197 &sensor_dev_attr_temp3_input.dev_attr.attr,
1198 &sensor_dev_attr_temp4_input.dev_attr.attr,
1199 &sensor_dev_attr_temp5_input.dev_attr.attr,
1200 &sensor_dev_attr_temp6_input.dev_attr.attr,
1201 &sensor_dev_attr_temp7_input.dev_attr.attr,
1202 &sensor_dev_attr_temp8_input.dev_attr.attr,
1203 &sensor_dev_attr_temp9_input.dev_attr.attr,
1204 &sensor_dev_attr_temp10_input.dev_attr.attr,
1205 &sensor_dev_attr_temp11_input.dev_attr.attr,
1206 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001207 &sensor_dev_attr_temp13_input.dev_attr.attr,
1208 &sensor_dev_attr_temp14_input.dev_attr.attr,
1209 &sensor_dev_attr_temp15_input.dev_attr.attr,
1210 &sensor_dev_attr_temp16_input.dev_attr.attr,
1211 &sensor_dev_attr_temp17_input.dev_attr.attr,
1212 &sensor_dev_attr_temp18_input.dev_attr.attr,
1213 &sensor_dev_attr_temp19_input.dev_attr.attr,
1214 &sensor_dev_attr_temp20_input.dev_attr.attr,
1215 &sensor_dev_attr_temp21_input.dev_attr.attr,
1216 &sensor_dev_attr_temp22_input.dev_attr.attr,
1217 &sensor_dev_attr_temp23_input.dev_attr.attr,
1218 &sensor_dev_attr_temp24_input.dev_attr.attr,
1219 &sensor_dev_attr_temp25_input.dev_attr.attr,
1220 &sensor_dev_attr_temp26_input.dev_attr.attr,
1221 &sensor_dev_attr_temp27_input.dev_attr.attr,
1222 &sensor_dev_attr_temp28_input.dev_attr.attr,
1223 &sensor_dev_attr_temp29_input.dev_attr.attr,
1224 &sensor_dev_attr_temp30_input.dev_attr.attr,
1225 &sensor_dev_attr_temp31_input.dev_attr.attr,
1226 &sensor_dev_attr_temp32_input.dev_attr.attr,
1227 &sensor_dev_attr_temp33_input.dev_attr.attr,
1228 &sensor_dev_attr_temp34_input.dev_attr.attr,
1229 &sensor_dev_attr_temp35_input.dev_attr.attr,
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001230 &sensor_dev_attr_temp36_input.dev_attr.attr,
1231 &sensor_dev_attr_temp37_input.dev_attr.attr,
1232 &sensor_dev_attr_temp38_input.dev_attr.attr,
1233 &sensor_dev_attr_temp39_input.dev_attr.attr,
1234 &sensor_dev_attr_temp40_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001235 NULL
1236};
1237
1238static const struct attribute_group temperature_attributes_group =
1239 { .attrs = temperature_attributes };
1240
1241/* Module stuff */
1242
1243/*
1244 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1245 */
Jeff Garzik18552562007-10-03 15:15:40 -04001246static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001247{
1248 int i = 0;
1249 struct dmi_match_data* dmi_data = id->driver_data;
1250 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1251 applesmc_accelerometer = dmi_data->accelerometer;
1252 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1253 applesmc_accelerometer ? "with" : "without");
1254 applesmc_light = dmi_data->light;
1255 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1256 applesmc_light ? "with" : "without");
1257
1258 applesmc_temperature_set = dmi_data->temperature_set;
1259 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1260 i++;
1261 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1262 return 1;
1263}
1264
1265/* Create accelerometer ressources */
1266static int applesmc_create_accelerometer(void)
1267{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001268 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001269 int ret;
1270
1271 ret = sysfs_create_group(&pdev->dev.kobj,
1272 &accelerometer_attributes_group);
1273 if (ret)
1274 goto out;
1275
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001276 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001277 if (!applesmc_idev) {
1278 ret = -ENOMEM;
1279 goto out_sysfs;
1280 }
1281
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001282 applesmc_idev->poll = applesmc_idev_poll;
1283 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1284
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001285 /* initial calibrate for the input device */
1286 applesmc_calibrate();
1287
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001288 /* initialize the input device */
1289 idev = applesmc_idev->input;
1290 idev->name = "applesmc";
1291 idev->id.bustype = BUS_HOST;
1292 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001293 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001294 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001295 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001296 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001297 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1298
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001299 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001300 if (ret)
1301 goto out_idev;
1302
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001303 return 0;
1304
1305out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001306 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001307
1308out_sysfs:
1309 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1310
1311out:
1312 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1313 return ret;
1314}
1315
1316/* Release all ressources used by the accelerometer */
1317static void applesmc_release_accelerometer(void)
1318{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001319 input_unregister_polled_device(applesmc_idev);
1320 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001321 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1322}
1323
1324static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1325/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1326 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001327/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001328 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001329/* MacBook: accelerometer and temperature set 2 */
1330 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1331/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001332 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001333/* MacPro: temperature set 4 */
1334 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001335/* iMac: temperature set 5 */
1336 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Henrik Rydberg468cc032008-11-12 13:24:58 -08001337/* MacBook3, MacBook4: accelerometer and temperature set 6 */
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001338 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001339/* MacBook Air: accelerometer, backlight and temperature set 7 */
1340 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001341/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1342 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001343/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1344 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001345/* iMac 5: light sensor only, temperature set 10 */
1346 { .accelerometer = 0, .light = 0, .temperature_set = 10 },
Henrik Rydberg181209a12008-11-06 12:53:20 -08001347/* MacBook 5: accelerometer, backlight and temperature set 11 */
1348 { .accelerometer = 1, .light = 1, .temperature_set = 11 },
Henrik Rydberga6660322008-11-06 12:53:21 -08001349/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
1350 { .accelerometer = 1, .light = 1, .temperature_set = 12 },
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001351/* iMac 8: light sensor only, temperature set 13 */
1352 { .accelerometer = 0, .light = 0, .temperature_set = 13 },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001353/* iMac 6: light sensor only, temperature set 14 */
1354 { .accelerometer = 0, .light = 0, .temperature_set = 14 },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001355/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
1356 { .accelerometer = 1, .light = 1, .temperature_set = 15 },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001357/* MacPro3,1: temperature set 16 */
1358 { .accelerometer = 0, .light = 0, .temperature_set = 16 },
Justin P. Mattocke1741712010-04-14 16:14:10 +02001359/* iMac 9,1: light sensor only, temperature set 17 */
1360 { .accelerometer = 0, .light = 0, .temperature_set = 17 },
1361/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
1362 { .accelerometer = 1, .light = 1, .temperature_set = 18 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001363};
1364
1365/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1366 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1367static __initdata struct dmi_system_id applesmc_whitelist[] = {
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001368 { applesmc_dmi_match, "Apple MacBook Air 2", {
1369 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1370 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
1371 &applesmc_dmi_data[15]},
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001372 { applesmc_dmi_match, "Apple MacBook Air", {
1373 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1374 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001375 &applesmc_dmi_data[7]},
Henrik Rydberga6660322008-11-06 12:53:21 -08001376 { applesmc_dmi_match, "Apple MacBook Pro 5", {
1377 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1378 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
1379 &applesmc_dmi_data[12]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001380 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1381 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1382 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1383 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001384 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1385 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1386 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1387 &applesmc_dmi_data[9]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001388 { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
1389 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
1390 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
1391 &applesmc_dmi_data[18]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001392 { applesmc_dmi_match, "Apple MacBook Pro", {
1393 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1394 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001395 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001396 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001397 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001398 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001399 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001400 { applesmc_dmi_match, "Apple MacBook (v3)", {
1401 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1402 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001403 &applesmc_dmi_data[6]},
Henrik Rydberg468cc032008-11-12 13:24:58 -08001404 { applesmc_dmi_match, "Apple MacBook 4", {
1405 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1406 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
1407 &applesmc_dmi_data[6]},
Henrik Rydberg181209a12008-11-06 12:53:20 -08001408 { applesmc_dmi_match, "Apple MacBook 5", {
1409 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1410 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
1411 &applesmc_dmi_data[11]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001412 { applesmc_dmi_match, "Apple MacBook", {
1413 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1414 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001415 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001416 { applesmc_dmi_match, "Apple Macmini", {
1417 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1418 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001419 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001420 { applesmc_dmi_match, "Apple MacPro2", {
1421 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1422 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001423 &applesmc_dmi_data[4]},
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001424 { applesmc_dmi_match, "Apple MacPro3", {
1425 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1426 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
1427 &applesmc_dmi_data[16]},
Henrik Rydberg45a3a362008-11-19 15:36:42 -08001428 { applesmc_dmi_match, "Apple MacPro", {
1429 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1430 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1431 &applesmc_dmi_data[4]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001432 { applesmc_dmi_match, "Apple iMac 9,1", {
1433 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
1434 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
1435 &applesmc_dmi_data[17]},
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001436 { applesmc_dmi_match, "Apple iMac 8", {
1437 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1438 DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
1439 &applesmc_dmi_data[13]},
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001440 { applesmc_dmi_match, "Apple iMac 6", {
1441 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1442 DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
1443 &applesmc_dmi_data[14]},
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001444 { applesmc_dmi_match, "Apple iMac 5", {
1445 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1446 DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
1447 &applesmc_dmi_data[10]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001448 { applesmc_dmi_match, "Apple iMac", {
1449 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1450 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001451 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001452 { .ident = NULL }
1453};
1454
1455static int __init applesmc_init(void)
1456{
1457 int ret;
1458 int count;
1459 int i;
1460
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001461 if (!dmi_check_system(applesmc_whitelist)) {
1462 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1463 ret = -ENODEV;
1464 goto out;
1465 }
1466
1467 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1468 "applesmc")) {
1469 ret = -ENXIO;
1470 goto out;
1471 }
1472
1473 ret = platform_driver_register(&applesmc_driver);
1474 if (ret)
1475 goto out_region;
1476
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001477 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1478 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001479 if (IS_ERR(pdev)) {
1480 ret = PTR_ERR(pdev);
1481 goto out_driver;
1482 }
1483
Nicolas Boichatfa744192007-05-23 13:58:13 -07001484 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001485 if (ret)
1486 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001487
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001488 /* Create key enumeration sysfs files */
1489 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1490 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001491 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001492
1493 /* create fan files */
1494 count = applesmc_get_fan_count();
1495 if (count < 0) {
1496 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
1497 } else {
1498 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1499
1500 switch (count) {
1501 default:
René Rebe8de57702007-10-16 14:19:20 -07001502 printk(KERN_WARNING "applesmc: More than 4 fans found,"
1503 " but at most 4 fans are supported"
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001504 " by the driver.\n");
René Rebe8de57702007-10-16 14:19:20 -07001505 case 4:
1506 ret = sysfs_create_group(&pdev->dev.kobj,
1507 &fan_attribute_groups[3]);
1508 if (ret)
1509 goto out_key_enumeration;
1510 case 3:
1511 ret = sysfs_create_group(&pdev->dev.kobj,
1512 &fan_attribute_groups[2]);
1513 if (ret)
1514 goto out_key_enumeration;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001515 case 2:
1516 ret = sysfs_create_group(&pdev->dev.kobj,
1517 &fan_attribute_groups[1]);
1518 if (ret)
1519 goto out_key_enumeration;
1520 case 1:
1521 ret = sysfs_create_group(&pdev->dev.kobj,
1522 &fan_attribute_groups[0]);
1523 if (ret)
1524 goto out_fan_1;
1525 case 0:
1526 ;
1527 }
1528 }
1529
1530 for (i = 0;
1531 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1532 i++) {
1533 if (temperature_attributes[i] == NULL) {
1534 printk(KERN_ERR "applesmc: More temperature sensors "
1535 "in temperature_sensors_sets (at least %i)"
1536 "than available sysfs files in "
1537 "temperature_attributes (%i), please report "
1538 "this bug.\n", i, i-1);
1539 goto out_temperature;
1540 }
1541 ret = sysfs_create_file(&pdev->dev.kobj,
1542 temperature_attributes[i]);
1543 if (ret)
1544 goto out_temperature;
1545 }
1546
1547 if (applesmc_accelerometer) {
1548 ret = applesmc_create_accelerometer();
1549 if (ret)
1550 goto out_temperature;
1551 }
1552
1553 if (applesmc_light) {
1554 /* Add light sensor file */
1555 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1556 if (ret)
1557 goto out_accelerometer;
1558
1559 /* Create the workqueue */
1560 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1561 if (!applesmc_led_wq) {
1562 ret = -ENOMEM;
1563 goto out_light_sysfs;
1564 }
1565
1566 /* register as a led device */
1567 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1568 if (ret < 0)
1569 goto out_light_wq;
1570 }
1571
Tony Jones1beeffe2007-08-20 13:46:20 -07001572 hwmon_dev = hwmon_device_register(&pdev->dev);
1573 if (IS_ERR(hwmon_dev)) {
1574 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001575 goto out_light_ledclass;
1576 }
1577
1578 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1579
1580 return 0;
1581
1582out_light_ledclass:
1583 if (applesmc_light)
1584 led_classdev_unregister(&applesmc_backlight);
1585out_light_wq:
1586 if (applesmc_light)
1587 destroy_workqueue(applesmc_led_wq);
1588out_light_sysfs:
1589 if (applesmc_light)
1590 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1591out_accelerometer:
1592 if (applesmc_accelerometer)
1593 applesmc_release_accelerometer();
1594out_temperature:
1595 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1596 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1597out_fan_1:
1598 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1599out_key_enumeration:
1600 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001601out_name:
1602 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001603out_device:
1604 platform_device_unregister(pdev);
1605out_driver:
1606 platform_driver_unregister(&applesmc_driver);
1607out_region:
1608 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1609out:
1610 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1611 return ret;
1612}
1613
1614static void __exit applesmc_exit(void)
1615{
Tony Jones1beeffe2007-08-20 13:46:20 -07001616 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001617 if (applesmc_light) {
1618 led_classdev_unregister(&applesmc_backlight);
1619 destroy_workqueue(applesmc_led_wq);
1620 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1621 }
1622 if (applesmc_accelerometer)
1623 applesmc_release_accelerometer();
1624 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1625 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1626 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1627 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001628 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001629 platform_device_unregister(pdev);
1630 platform_driver_unregister(&applesmc_driver);
1631 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1632
1633 printk(KERN_INFO "applesmc: driver unloaded.\n");
1634}
1635
1636module_init(applesmc_init);
1637module_exit(applesmc_exit);
1638
1639MODULE_AUTHOR("Nicolas Boichat");
1640MODULE_DESCRIPTION("Apple SMC");
1641MODULE_LICENSE("GPL v2");
Henrik Rydbergdc924ef2008-12-01 13:13:49 -08001642MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);