blob: f085c18d2905a602d465ef01a8d08b2a29467c28 [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 Rydberg181209a2008-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
Henrik Rydberg0559a532010-05-11 09:17:47 +0200198/* The number of fans handled by the driver */
199static unsigned int fans_handled;
200
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700201/* Indicates which temperature sensors set to use. */
202static unsigned int applesmc_temperature_set;
203
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400204static DEFINE_MUTEX(applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700205
206/*
207 * Last index written to key_at_index sysfs file, and value to use for all other
208 * key_at_index_* sysfs files.
209 */
210static unsigned int key_at_index;
211
212static struct workqueue_struct *applesmc_led_wq;
213
214/*
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700215 * __wait_status - Wait up to 32ms for the status port to get a certain value
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700216 * (masked with 0x0f), returning zero if the value is obtained. Callers must
217 * hold applesmc_lock.
218 */
219static int __wait_status(u8 val)
220{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700221 int us;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700222
223 val = val & APPLESMC_STATUS_MASK;
224
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700225 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
226 udelay(us);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700227 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
228 if (debug)
229 printk(KERN_DEBUG
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700230 "Waited %d us for status %x\n",
231 2 * us - APPLESMC_MIN_WAIT, val);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700232 return 0;
233 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700234 }
235
236 printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
237 val, inb(APPLESMC_CMD_PORT));
238
239 return -EIO;
240}
241
242/*
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700243 * special treatment of command port - on newer macbooks, it seems necessary
244 * to resend the command byte before polling the status again. Callers must
245 * hold applesmc_lock.
246 */
247static int send_command(u8 cmd)
248{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700249 int us;
250 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700251 outb(cmd, APPLESMC_CMD_PORT);
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700252 udelay(us);
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700253 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
254 return 0;
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700255 }
256 printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
257 cmd, inb(APPLESMC_CMD_PORT));
258 return -EIO;
259}
260
261/*
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700262 * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
263 * Returns zero on success or a negative error on failure. Callers must
264 * hold applesmc_lock.
265 */
266static int applesmc_read_key(const char* key, u8* buffer, u8 len)
267{
268 int i;
269
270 if (len > APPLESMC_MAX_DATA_LENGTH) {
271 printk(KERN_ERR "applesmc_read_key: cannot read more than "
272 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
273 return -EINVAL;
274 }
275
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700276 if (send_command(APPLESMC_READ_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700277 return -EIO;
278
279 for (i = 0; i < 4; i++) {
280 outb(key[i], APPLESMC_DATA_PORT);
281 if (__wait_status(0x04))
282 return -EIO;
283 }
284 if (debug)
285 printk(KERN_DEBUG "<%s", key);
286
287 outb(len, APPLESMC_DATA_PORT);
288 if (debug)
289 printk(KERN_DEBUG ">%x", len);
290
291 for (i = 0; i < len; i++) {
292 if (__wait_status(0x05))
293 return -EIO;
294 buffer[i] = inb(APPLESMC_DATA_PORT);
295 if (debug)
296 printk(KERN_DEBUG "<%x", buffer[i]);
297 }
298 if (debug)
299 printk(KERN_DEBUG "\n");
300
301 return 0;
302}
303
304/*
305 * applesmc_write_key - writes len bytes from buffer to a given key.
306 * Returns zero on success or a negative error on failure. Callers must
307 * hold applesmc_lock.
308 */
309static int applesmc_write_key(const char* key, u8* buffer, u8 len)
310{
311 int i;
312
313 if (len > APPLESMC_MAX_DATA_LENGTH) {
314 printk(KERN_ERR "applesmc_write_key: cannot write more than "
315 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
316 return -EINVAL;
317 }
318
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700319 if (send_command(APPLESMC_WRITE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700320 return -EIO;
321
322 for (i = 0; i < 4; i++) {
323 outb(key[i], APPLESMC_DATA_PORT);
324 if (__wait_status(0x04))
325 return -EIO;
326 }
327
328 outb(len, APPLESMC_DATA_PORT);
329
330 for (i = 0; i < len; i++) {
331 if (__wait_status(0x04))
332 return -EIO;
333 outb(buffer[i], APPLESMC_DATA_PORT);
334 }
335
336 return 0;
337}
338
339/*
340 * applesmc_get_key_at_index - get key at index, and put the result in key
341 * (char[6]). Returns zero on success or a negative error on failure. Callers
342 * must hold applesmc_lock.
343 */
344static int applesmc_get_key_at_index(int index, char* key)
345{
346 int i;
347 u8 readkey[4];
348 readkey[0] = index >> 24;
349 readkey[1] = index >> 16;
350 readkey[2] = index >> 8;
351 readkey[3] = index;
352
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700353 if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700354 return -EIO;
355
356 for (i = 0; i < 4; i++) {
357 outb(readkey[i], APPLESMC_DATA_PORT);
358 if (__wait_status(0x04))
359 return -EIO;
360 }
361
362 outb(4, APPLESMC_DATA_PORT);
363
364 for (i = 0; i < 4; i++) {
365 if (__wait_status(0x05))
366 return -EIO;
367 key[i] = inb(APPLESMC_DATA_PORT);
368 }
369 key[4] = 0;
370
371 return 0;
372}
373
374/*
375 * applesmc_get_key_type - get key type, and put the result in type (char[6]).
376 * Returns zero on success or a negative error on failure. Callers must
377 * hold applesmc_lock.
378 */
379static int applesmc_get_key_type(char* key, char* type)
380{
381 int i;
382
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700383 if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700384 return -EIO;
385
386 for (i = 0; i < 4; i++) {
387 outb(key[i], APPLESMC_DATA_PORT);
388 if (__wait_status(0x04))
389 return -EIO;
390 }
391
Henrik Rydberg05224092008-10-18 20:27:35 -0700392 outb(6, APPLESMC_DATA_PORT);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700393
394 for (i = 0; i < 6; i++) {
395 if (__wait_status(0x05))
396 return -EIO;
397 type[i] = inb(APPLESMC_DATA_PORT);
398 }
399 type[5] = 0;
400
401 return 0;
402}
403
404/*
405 * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
406 * hold applesmc_lock.
407 */
408static int applesmc_read_motion_sensor(int index, s16* value)
409{
410 u8 buffer[2];
411 int ret;
412
413 switch (index) {
414 case SENSOR_X:
415 ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
416 break;
417 case SENSOR_Y:
418 ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
419 break;
420 case SENSOR_Z:
421 ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
422 break;
423 default:
424 ret = -EINVAL;
425 }
426
427 *value = ((s16)buffer[0] << 8) | buffer[1];
428
429 return ret;
430}
431
432/*
433 * applesmc_device_init - initialize the accelerometer. Returns zero on success
434 * and negative error code on failure. Can sleep.
435 */
436static int applesmc_device_init(void)
437{
438 int total, ret = -ENXIO;
439 u8 buffer[2];
440
441 if (!applesmc_accelerometer)
442 return 0;
443
444 mutex_lock(&applesmc_lock);
445
446 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
447 if (debug)
448 printk(KERN_DEBUG "applesmc try %d\n", total);
449 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
450 (buffer[0] != 0x00 || buffer[1] != 0x00)) {
451 if (total == INIT_TIMEOUT_MSECS) {
452 printk(KERN_DEBUG "applesmc: device has"
453 " already been initialized"
454 " (0x%02x, 0x%02x).\n",
455 buffer[0], buffer[1]);
456 } else {
457 printk(KERN_DEBUG "applesmc: device"
458 " successfully initialized"
459 " (0x%02x, 0x%02x).\n",
460 buffer[0], buffer[1]);
461 }
462 ret = 0;
463 goto out;
464 }
465 buffer[0] = 0xe0;
466 buffer[1] = 0x00;
467 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
468 msleep(INIT_WAIT_MSECS);
469 }
470
471 printk(KERN_WARNING "applesmc: failed to init the device\n");
472
473out:
474 mutex_unlock(&applesmc_lock);
475 return ret;
476}
477
478/*
479 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
480 * applesmc_lock.
481 */
482static int applesmc_get_fan_count(void)
483{
484 int ret;
485 u8 buffer[1];
486
487 mutex_lock(&applesmc_lock);
488
489 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
490
491 mutex_unlock(&applesmc_lock);
492 if (ret)
493 return ret;
494 else
495 return buffer[0];
496}
497
498/* Device model stuff */
499static int applesmc_probe(struct platform_device *dev)
500{
501 int ret;
502
503 ret = applesmc_device_init();
504 if (ret)
505 return ret;
506
507 printk(KERN_INFO "applesmc: device successfully initialized.\n");
508 return 0;
509}
510
Henrik Rydberga976f152009-09-21 17:04:50 -0700511/* Synchronize device with memorized backlight state */
512static int applesmc_pm_resume(struct device *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700513{
Henrik Rydberga976f152009-09-21 17:04:50 -0700514 mutex_lock(&applesmc_lock);
515 if (applesmc_light)
516 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
517 mutex_unlock(&applesmc_lock);
518 return 0;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700519}
520
Henrik Rydberga976f152009-09-21 17:04:50 -0700521/* Reinitialize device on resume from hibernation */
522static int applesmc_pm_restore(struct device *dev)
523{
524 int ret = applesmc_device_init();
525 if (ret)
526 return ret;
527 return applesmc_pm_resume(dev);
528}
529
Alexey Dobriyan47145212009-12-14 18:00:08 -0800530static const struct dev_pm_ops applesmc_pm_ops = {
Henrik Rydberga976f152009-09-21 17:04:50 -0700531 .resume = applesmc_pm_resume,
532 .restore = applesmc_pm_restore,
533};
534
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700535static struct platform_driver applesmc_driver = {
536 .probe = applesmc_probe,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700537 .driver = {
538 .name = "applesmc",
539 .owner = THIS_MODULE,
Henrik Rydberga976f152009-09-21 17:04:50 -0700540 .pm = &applesmc_pm_ops,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700541 },
542};
543
544/*
545 * applesmc_calibrate - Set our "resting" values. Callers must
546 * hold applesmc_lock.
547 */
548static void applesmc_calibrate(void)
549{
550 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
551 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
552 rest_x = -rest_x;
553}
554
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400555static void applesmc_idev_poll(struct input_polled_dev *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700556{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400557 struct input_dev *idev = dev->input;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700558 s16 x, y;
559
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400560 mutex_lock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700561
562 if (applesmc_read_motion_sensor(SENSOR_X, &x))
563 goto out;
564 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
565 goto out;
566
567 x = -x;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400568 input_report_abs(idev, ABS_X, x - rest_x);
569 input_report_abs(idev, ABS_Y, y - rest_y);
570 input_sync(idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700571
572out:
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700573 mutex_unlock(&applesmc_lock);
574}
575
576/* Sysfs Files */
577
Nicolas Boichatfa744192007-05-23 13:58:13 -0700578static ssize_t applesmc_name_show(struct device *dev,
579 struct device_attribute *attr, char *buf)
580{
581 return snprintf(buf, PAGE_SIZE, "applesmc\n");
582}
583
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700584static ssize_t applesmc_position_show(struct device *dev,
585 struct device_attribute *attr, char *buf)
586{
587 int ret;
588 s16 x, y, z;
589
590 mutex_lock(&applesmc_lock);
591
592 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
593 if (ret)
594 goto out;
595 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
596 if (ret)
597 goto out;
598 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
599 if (ret)
600 goto out;
601
602out:
603 mutex_unlock(&applesmc_lock);
604 if (ret)
605 return ret;
606 else
607 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
608}
609
610static ssize_t applesmc_light_show(struct device *dev,
611 struct device_attribute *attr, char *sysfsbuf)
612{
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700613 static int data_length;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700614 int ret;
615 u8 left = 0, right = 0;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700616 u8 buffer[10], query[6];
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700617
618 mutex_lock(&applesmc_lock);
619
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700620 if (!data_length) {
621 ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
622 if (ret)
623 goto out;
624 data_length = clamp_val(query[0], 0, 10);
625 printk(KERN_INFO "applesmc: light sensor data length set to "
626 "%d\n", data_length);
627 }
628
629 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Alex Murrayc3d63622009-01-15 13:51:08 -0800630 /* newer macbooks report a single 10-bit bigendian value */
631 if (data_length == 10) {
632 left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
633 goto out;
634 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700635 left = buffer[2];
636 if (ret)
637 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700638 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700639 right = buffer[2];
640
641out:
642 mutex_unlock(&applesmc_lock);
643 if (ret)
644 return ret;
645 else
646 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
647}
648
649/* Displays degree Celsius * 1000 */
650static ssize_t applesmc_show_temperature(struct device *dev,
651 struct device_attribute *devattr, char *sysfsbuf)
652{
653 int ret;
654 u8 buffer[2];
655 unsigned int temp;
656 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
657 const char* key =
658 temperature_sensors_sets[applesmc_temperature_set][attr->index];
659
660 mutex_lock(&applesmc_lock);
661
662 ret = applesmc_read_key(key, buffer, 2);
663 temp = buffer[0]*1000;
664 temp += (buffer[1] >> 6) * 250;
665
666 mutex_unlock(&applesmc_lock);
667
668 if (ret)
669 return ret;
670 else
671 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
672}
673
674static ssize_t applesmc_show_fan_speed(struct device *dev,
675 struct device_attribute *attr, char *sysfsbuf)
676{
677 int ret;
678 unsigned int speed = 0;
679 char newkey[5];
680 u8 buffer[2];
681 struct sensor_device_attribute_2 *sensor_attr =
682 to_sensor_dev_attr_2(attr);
683
684 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
685 newkey[1] = '0' + sensor_attr->index;
686 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
687 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
688 newkey[4] = 0;
689
690 mutex_lock(&applesmc_lock);
691
692 ret = applesmc_read_key(newkey, buffer, 2);
693 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
694
695 mutex_unlock(&applesmc_lock);
696 if (ret)
697 return ret;
698 else
699 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
700}
701
702static ssize_t applesmc_store_fan_speed(struct device *dev,
703 struct device_attribute *attr,
704 const char *sysfsbuf, size_t count)
705{
706 int ret;
707 u32 speed;
708 char newkey[5];
709 u8 buffer[2];
710 struct sensor_device_attribute_2 *sensor_attr =
711 to_sensor_dev_attr_2(attr);
712
713 speed = simple_strtoul(sysfsbuf, NULL, 10);
714
715 if (speed > 0x4000) /* Bigger than a 14-bit value */
716 return -EINVAL;
717
718 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
719 newkey[1] = '0' + sensor_attr->index;
720 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
721 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
722 newkey[4] = 0;
723
724 mutex_lock(&applesmc_lock);
725
726 buffer[0] = (speed >> 6) & 0xff;
727 buffer[1] = (speed << 2) & 0xff;
728 ret = applesmc_write_key(newkey, buffer, 2);
729
730 mutex_unlock(&applesmc_lock);
731 if (ret)
732 return ret;
733 else
734 return count;
735}
736
737static ssize_t applesmc_show_fan_manual(struct device *dev,
738 struct device_attribute *devattr, char *sysfsbuf)
739{
740 int ret;
741 u16 manual = 0;
742 u8 buffer[2];
743 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
744
745 mutex_lock(&applesmc_lock);
746
747 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
748 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
749
750 mutex_unlock(&applesmc_lock);
751 if (ret)
752 return ret;
753 else
754 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
755}
756
757static ssize_t applesmc_store_fan_manual(struct device *dev,
758 struct device_attribute *devattr,
759 const char *sysfsbuf, size_t count)
760{
761 int ret;
762 u8 buffer[2];
763 u32 input;
764 u16 val;
765 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
766
767 input = simple_strtoul(sysfsbuf, NULL, 10);
768
769 mutex_lock(&applesmc_lock);
770
771 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
772 val = (buffer[0] << 8 | buffer[1]);
773 if (ret)
774 goto out;
775
776 if (input)
777 val = val | (0x01 << attr->index);
778 else
779 val = val & ~(0x01 << attr->index);
780
781 buffer[0] = (val >> 8) & 0xFF;
782 buffer[1] = val & 0xFF;
783
784 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
785
786out:
787 mutex_unlock(&applesmc_lock);
788 if (ret)
789 return ret;
790 else
791 return count;
792}
793
794static ssize_t applesmc_show_fan_position(struct device *dev,
795 struct device_attribute *attr, char *sysfsbuf)
796{
797 int ret;
798 char newkey[5];
799 u8 buffer[17];
800 struct sensor_device_attribute_2 *sensor_attr =
801 to_sensor_dev_attr_2(attr);
802
803 newkey[0] = FAN_POSITION[0];
804 newkey[1] = '0' + sensor_attr->index;
805 newkey[2] = FAN_POSITION[2];
806 newkey[3] = FAN_POSITION[3];
807 newkey[4] = 0;
808
809 mutex_lock(&applesmc_lock);
810
811 ret = applesmc_read_key(newkey, buffer, 16);
812 buffer[16] = 0;
813
814 mutex_unlock(&applesmc_lock);
815 if (ret)
816 return ret;
817 else
818 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
819}
820
821static ssize_t applesmc_calibrate_show(struct device *dev,
822 struct device_attribute *attr, char *sysfsbuf)
823{
824 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
825}
826
827static ssize_t applesmc_calibrate_store(struct device *dev,
828 struct device_attribute *attr, const char *sysfsbuf, size_t count)
829{
830 mutex_lock(&applesmc_lock);
831 applesmc_calibrate();
832 mutex_unlock(&applesmc_lock);
833
834 return count;
835}
836
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700837static void applesmc_backlight_set(struct work_struct *work)
838{
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700839 mutex_lock(&applesmc_lock);
Henrik Rydberga976f152009-09-21 17:04:50 -0700840 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700841 mutex_unlock(&applesmc_lock);
842}
843static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
844
845static void applesmc_brightness_set(struct led_classdev *led_cdev,
846 enum led_brightness value)
847{
848 int ret;
849
Henrik Rydberga976f152009-09-21 17:04:50 -0700850 backlight_state[0] = value;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700851 ret = queue_work(applesmc_led_wq, &backlight_work);
852
853 if (debug && (!ret))
854 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
855}
856
857static ssize_t applesmc_key_count_show(struct device *dev,
858 struct device_attribute *attr, char *sysfsbuf)
859{
860 int ret;
861 u8 buffer[4];
862 u32 count;
863
864 mutex_lock(&applesmc_lock);
865
866 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
867 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
868 ((u32)buffer[2]<<8) + buffer[3];
869
870 mutex_unlock(&applesmc_lock);
871 if (ret)
872 return ret;
873 else
874 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
875}
876
877static ssize_t applesmc_key_at_index_read_show(struct device *dev,
878 struct device_attribute *attr, char *sysfsbuf)
879{
880 char key[5];
881 char info[6];
882 int ret;
883
884 mutex_lock(&applesmc_lock);
885
886 ret = applesmc_get_key_at_index(key_at_index, key);
887
888 if (ret || !key[0]) {
889 mutex_unlock(&applesmc_lock);
890
891 return -EINVAL;
892 }
893
894 ret = applesmc_get_key_type(key, info);
895
896 if (ret) {
897 mutex_unlock(&applesmc_lock);
898
899 return ret;
900 }
901
902 /*
903 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
904 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
905 */
906 ret = applesmc_read_key(key, sysfsbuf, info[0]);
907
908 mutex_unlock(&applesmc_lock);
909
910 if (!ret) {
911 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400912 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700913 return ret;
914 }
915}
916
917static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
918 struct device_attribute *attr, char *sysfsbuf)
919{
920 char key[5];
921 char info[6];
922 int ret;
923
924 mutex_lock(&applesmc_lock);
925
926 ret = applesmc_get_key_at_index(key_at_index, key);
927
928 if (ret || !key[0]) {
929 mutex_unlock(&applesmc_lock);
930
931 return -EINVAL;
932 }
933
934 ret = applesmc_get_key_type(key, info);
935
936 mutex_unlock(&applesmc_lock);
937
938 if (!ret)
939 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
940 else
941 return ret;
942}
943
944static ssize_t applesmc_key_at_index_type_show(struct device *dev,
945 struct device_attribute *attr, char *sysfsbuf)
946{
947 char key[5];
948 char info[6];
949 int ret;
950
951 mutex_lock(&applesmc_lock);
952
953 ret = applesmc_get_key_at_index(key_at_index, key);
954
955 if (ret || !key[0]) {
956 mutex_unlock(&applesmc_lock);
957
958 return -EINVAL;
959 }
960
961 ret = applesmc_get_key_type(key, info);
962
963 mutex_unlock(&applesmc_lock);
964
965 if (!ret)
966 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
967 else
968 return ret;
969}
970
971static ssize_t applesmc_key_at_index_name_show(struct device *dev,
972 struct device_attribute *attr, char *sysfsbuf)
973{
974 char key[5];
975 int ret;
976
977 mutex_lock(&applesmc_lock);
978
979 ret = applesmc_get_key_at_index(key_at_index, key);
980
981 mutex_unlock(&applesmc_lock);
982
983 if (!ret && key[0])
984 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
985 else
986 return -EINVAL;
987}
988
989static ssize_t applesmc_key_at_index_show(struct device *dev,
990 struct device_attribute *attr, char *sysfsbuf)
991{
992 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
993}
994
995static ssize_t applesmc_key_at_index_store(struct device *dev,
996 struct device_attribute *attr, const char *sysfsbuf, size_t count)
997{
998 mutex_lock(&applesmc_lock);
999
1000 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
1001
1002 mutex_unlock(&applesmc_lock);
1003
1004 return count;
1005}
1006
1007static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +01001008 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001009 .default_trigger = "nand-disk",
1010 .brightness_set = applesmc_brightness_set,
1011};
1012
Nicolas Boichatfa744192007-05-23 13:58:13 -07001013static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
1014
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001015static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
1016static DEVICE_ATTR(calibrate, 0644,
1017 applesmc_calibrate_show, applesmc_calibrate_store);
1018
1019static struct attribute *accelerometer_attributes[] = {
1020 &dev_attr_position.attr,
1021 &dev_attr_calibrate.attr,
1022 NULL
1023};
1024
1025static const struct attribute_group accelerometer_attributes_group =
1026 { .attrs = accelerometer_attributes };
1027
1028static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
1029
1030static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
1031static DEVICE_ATTR(key_at_index, 0644,
1032 applesmc_key_at_index_show, applesmc_key_at_index_store);
1033static DEVICE_ATTR(key_at_index_name, 0444,
1034 applesmc_key_at_index_name_show, NULL);
1035static DEVICE_ATTR(key_at_index_type, 0444,
1036 applesmc_key_at_index_type_show, NULL);
1037static DEVICE_ATTR(key_at_index_data_length, 0444,
1038 applesmc_key_at_index_data_length_show, NULL);
1039static DEVICE_ATTR(key_at_index_data, 0444,
1040 applesmc_key_at_index_read_show, NULL);
1041
1042static struct attribute *key_enumeration_attributes[] = {
1043 &dev_attr_key_count.attr,
1044 &dev_attr_key_at_index.attr,
1045 &dev_attr_key_at_index_name.attr,
1046 &dev_attr_key_at_index_type.attr,
1047 &dev_attr_key_at_index_data_length.attr,
1048 &dev_attr_key_at_index_data.attr,
1049 NULL
1050};
1051
1052static const struct attribute_group key_enumeration_group =
1053 { .attrs = key_enumeration_attributes };
1054
1055/*
1056 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1057 * - show actual speed
1058 * - show/store minimum speed
1059 * - show maximum speed
1060 * - show safe speed
1061 * - show/store target speed
1062 * - show/store manual mode
1063 */
1064#define sysfs_fan_speeds_offset(offset) \
1065static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1066 applesmc_show_fan_speed, NULL, 0, offset-1); \
1067\
1068static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1069 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1070\
1071static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1072 applesmc_show_fan_speed, NULL, 2, offset-1); \
1073\
1074static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1075 applesmc_show_fan_speed, NULL, 3, offset-1); \
1076\
1077static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1078 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1079\
1080static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1081 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1082\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001083static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001084 applesmc_show_fan_position, NULL, offset-1); \
1085\
1086static struct attribute *fan##offset##_attributes[] = { \
1087 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1088 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1089 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1090 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1091 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1092 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001093 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001094 NULL \
1095};
1096
1097/*
1098 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001099 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001100 */
1101sysfs_fan_speeds_offset(1);
1102sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001103sysfs_fan_speeds_offset(3);
1104sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001105
1106static const struct attribute_group fan_attribute_groups[] = {
1107 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001108 { .attrs = fan2_attributes },
1109 { .attrs = fan3_attributes },
1110 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001111};
1112
1113/*
1114 * Temperature sensors sysfs entries.
1115 */
1116static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1117 applesmc_show_temperature, NULL, 0);
1118static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1119 applesmc_show_temperature, NULL, 1);
1120static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1121 applesmc_show_temperature, NULL, 2);
1122static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1123 applesmc_show_temperature, NULL, 3);
1124static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1125 applesmc_show_temperature, NULL, 4);
1126static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1127 applesmc_show_temperature, NULL, 5);
1128static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1129 applesmc_show_temperature, NULL, 6);
1130static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1131 applesmc_show_temperature, NULL, 7);
1132static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1133 applesmc_show_temperature, NULL, 8);
1134static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1135 applesmc_show_temperature, NULL, 9);
1136static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1137 applesmc_show_temperature, NULL, 10);
1138static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1139 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001140static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1141 applesmc_show_temperature, NULL, 12);
1142static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1143 applesmc_show_temperature, NULL, 13);
1144static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1145 applesmc_show_temperature, NULL, 14);
1146static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1147 applesmc_show_temperature, NULL, 15);
1148static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1149 applesmc_show_temperature, NULL, 16);
1150static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1151 applesmc_show_temperature, NULL, 17);
1152static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1153 applesmc_show_temperature, NULL, 18);
1154static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1155 applesmc_show_temperature, NULL, 19);
1156static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1157 applesmc_show_temperature, NULL, 20);
1158static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1159 applesmc_show_temperature, NULL, 21);
1160static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1161 applesmc_show_temperature, NULL, 22);
1162static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1163 applesmc_show_temperature, NULL, 23);
1164static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1165 applesmc_show_temperature, NULL, 24);
1166static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1167 applesmc_show_temperature, NULL, 25);
1168static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1169 applesmc_show_temperature, NULL, 26);
1170static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1171 applesmc_show_temperature, NULL, 27);
1172static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1173 applesmc_show_temperature, NULL, 28);
1174static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1175 applesmc_show_temperature, NULL, 29);
1176static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1177 applesmc_show_temperature, NULL, 30);
1178static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1179 applesmc_show_temperature, NULL, 31);
1180static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1181 applesmc_show_temperature, NULL, 32);
1182static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1183 applesmc_show_temperature, NULL, 33);
1184static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1185 applesmc_show_temperature, NULL, 34);
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001186static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
1187 applesmc_show_temperature, NULL, 35);
1188static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
1189 applesmc_show_temperature, NULL, 36);
1190static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
1191 applesmc_show_temperature, NULL, 37);
1192static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
1193 applesmc_show_temperature, NULL, 38);
1194static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
1195 applesmc_show_temperature, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001196
1197static struct attribute *temperature_attributes[] = {
1198 &sensor_dev_attr_temp1_input.dev_attr.attr,
1199 &sensor_dev_attr_temp2_input.dev_attr.attr,
1200 &sensor_dev_attr_temp3_input.dev_attr.attr,
1201 &sensor_dev_attr_temp4_input.dev_attr.attr,
1202 &sensor_dev_attr_temp5_input.dev_attr.attr,
1203 &sensor_dev_attr_temp6_input.dev_attr.attr,
1204 &sensor_dev_attr_temp7_input.dev_attr.attr,
1205 &sensor_dev_attr_temp8_input.dev_attr.attr,
1206 &sensor_dev_attr_temp9_input.dev_attr.attr,
1207 &sensor_dev_attr_temp10_input.dev_attr.attr,
1208 &sensor_dev_attr_temp11_input.dev_attr.attr,
1209 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001210 &sensor_dev_attr_temp13_input.dev_attr.attr,
1211 &sensor_dev_attr_temp14_input.dev_attr.attr,
1212 &sensor_dev_attr_temp15_input.dev_attr.attr,
1213 &sensor_dev_attr_temp16_input.dev_attr.attr,
1214 &sensor_dev_attr_temp17_input.dev_attr.attr,
1215 &sensor_dev_attr_temp18_input.dev_attr.attr,
1216 &sensor_dev_attr_temp19_input.dev_attr.attr,
1217 &sensor_dev_attr_temp20_input.dev_attr.attr,
1218 &sensor_dev_attr_temp21_input.dev_attr.attr,
1219 &sensor_dev_attr_temp22_input.dev_attr.attr,
1220 &sensor_dev_attr_temp23_input.dev_attr.attr,
1221 &sensor_dev_attr_temp24_input.dev_attr.attr,
1222 &sensor_dev_attr_temp25_input.dev_attr.attr,
1223 &sensor_dev_attr_temp26_input.dev_attr.attr,
1224 &sensor_dev_attr_temp27_input.dev_attr.attr,
1225 &sensor_dev_attr_temp28_input.dev_attr.attr,
1226 &sensor_dev_attr_temp29_input.dev_attr.attr,
1227 &sensor_dev_attr_temp30_input.dev_attr.attr,
1228 &sensor_dev_attr_temp31_input.dev_attr.attr,
1229 &sensor_dev_attr_temp32_input.dev_attr.attr,
1230 &sensor_dev_attr_temp33_input.dev_attr.attr,
1231 &sensor_dev_attr_temp34_input.dev_attr.attr,
1232 &sensor_dev_attr_temp35_input.dev_attr.attr,
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001233 &sensor_dev_attr_temp36_input.dev_attr.attr,
1234 &sensor_dev_attr_temp37_input.dev_attr.attr,
1235 &sensor_dev_attr_temp38_input.dev_attr.attr,
1236 &sensor_dev_attr_temp39_input.dev_attr.attr,
1237 &sensor_dev_attr_temp40_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001238 NULL
1239};
1240
1241static const struct attribute_group temperature_attributes_group =
1242 { .attrs = temperature_attributes };
1243
1244/* Module stuff */
1245
1246/*
1247 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1248 */
Jeff Garzik18552562007-10-03 15:15:40 -04001249static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001250{
1251 int i = 0;
1252 struct dmi_match_data* dmi_data = id->driver_data;
1253 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1254 applesmc_accelerometer = dmi_data->accelerometer;
1255 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1256 applesmc_accelerometer ? "with" : "without");
1257 applesmc_light = dmi_data->light;
1258 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1259 applesmc_light ? "with" : "without");
1260
1261 applesmc_temperature_set = dmi_data->temperature_set;
1262 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1263 i++;
1264 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1265 return 1;
1266}
1267
1268/* Create accelerometer ressources */
1269static int applesmc_create_accelerometer(void)
1270{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001271 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001272 int ret;
1273
1274 ret = sysfs_create_group(&pdev->dev.kobj,
1275 &accelerometer_attributes_group);
1276 if (ret)
1277 goto out;
1278
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001279 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001280 if (!applesmc_idev) {
1281 ret = -ENOMEM;
1282 goto out_sysfs;
1283 }
1284
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001285 applesmc_idev->poll = applesmc_idev_poll;
1286 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1287
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001288 /* initial calibrate for the input device */
1289 applesmc_calibrate();
1290
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001291 /* initialize the input device */
1292 idev = applesmc_idev->input;
1293 idev->name = "applesmc";
1294 idev->id.bustype = BUS_HOST;
1295 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001296 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001297 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001298 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001299 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001300 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1301
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001302 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001303 if (ret)
1304 goto out_idev;
1305
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001306 return 0;
1307
1308out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001309 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001310
1311out_sysfs:
1312 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1313
1314out:
1315 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1316 return ret;
1317}
1318
1319/* Release all ressources used by the accelerometer */
1320static void applesmc_release_accelerometer(void)
1321{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001322 input_unregister_polled_device(applesmc_idev);
1323 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001324 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1325}
1326
1327static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1328/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1329 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001330/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001331 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001332/* MacBook: accelerometer and temperature set 2 */
1333 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1334/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001335 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001336/* MacPro: temperature set 4 */
1337 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001338/* iMac: temperature set 5 */
1339 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Henrik Rydberg468cc032008-11-12 13:24:58 -08001340/* MacBook3, MacBook4: accelerometer and temperature set 6 */
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001341 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001342/* MacBook Air: accelerometer, backlight and temperature set 7 */
1343 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001344/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1345 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001346/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1347 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001348/* iMac 5: light sensor only, temperature set 10 */
1349 { .accelerometer = 0, .light = 0, .temperature_set = 10 },
Henrik Rydberg181209a2008-11-06 12:53:20 -08001350/* MacBook 5: accelerometer, backlight and temperature set 11 */
1351 { .accelerometer = 1, .light = 1, .temperature_set = 11 },
Henrik Rydberga6660322008-11-06 12:53:21 -08001352/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
1353 { .accelerometer = 1, .light = 1, .temperature_set = 12 },
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001354/* iMac 8: light sensor only, temperature set 13 */
1355 { .accelerometer = 0, .light = 0, .temperature_set = 13 },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001356/* iMac 6: light sensor only, temperature set 14 */
1357 { .accelerometer = 0, .light = 0, .temperature_set = 14 },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001358/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
1359 { .accelerometer = 1, .light = 1, .temperature_set = 15 },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001360/* MacPro3,1: temperature set 16 */
1361 { .accelerometer = 0, .light = 0, .temperature_set = 16 },
Justin P. Mattocke1741712010-04-14 16:14:10 +02001362/* iMac 9,1: light sensor only, temperature set 17 */
1363 { .accelerometer = 0, .light = 0, .temperature_set = 17 },
1364/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
1365 { .accelerometer = 1, .light = 1, .temperature_set = 18 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001366};
1367
1368/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1369 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1370static __initdata struct dmi_system_id applesmc_whitelist[] = {
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001371 { applesmc_dmi_match, "Apple MacBook Air 2", {
1372 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1373 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
1374 &applesmc_dmi_data[15]},
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001375 { applesmc_dmi_match, "Apple MacBook Air", {
1376 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1377 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001378 &applesmc_dmi_data[7]},
Henrik Rydberga6660322008-11-06 12:53:21 -08001379 { applesmc_dmi_match, "Apple MacBook Pro 5", {
1380 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1381 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
1382 &applesmc_dmi_data[12]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001383 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1384 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1385 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1386 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001387 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1388 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1389 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1390 &applesmc_dmi_data[9]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001391 { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
1392 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
1393 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
1394 &applesmc_dmi_data[18]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001395 { applesmc_dmi_match, "Apple MacBook Pro", {
1396 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1397 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001398 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001399 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001400 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001401 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001402 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001403 { applesmc_dmi_match, "Apple MacBook (v3)", {
1404 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1405 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001406 &applesmc_dmi_data[6]},
Henrik Rydberg468cc032008-11-12 13:24:58 -08001407 { applesmc_dmi_match, "Apple MacBook 4", {
1408 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1409 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
1410 &applesmc_dmi_data[6]},
Henrik Rydberg181209a2008-11-06 12:53:20 -08001411 { applesmc_dmi_match, "Apple MacBook 5", {
1412 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1413 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
1414 &applesmc_dmi_data[11]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001415 { applesmc_dmi_match, "Apple MacBook", {
1416 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1417 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001418 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001419 { applesmc_dmi_match, "Apple Macmini", {
1420 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1421 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001422 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001423 { applesmc_dmi_match, "Apple MacPro2", {
1424 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1425 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001426 &applesmc_dmi_data[4]},
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001427 { applesmc_dmi_match, "Apple MacPro3", {
1428 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1429 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
1430 &applesmc_dmi_data[16]},
Henrik Rydberg45a3a362008-11-19 15:36:42 -08001431 { applesmc_dmi_match, "Apple MacPro", {
1432 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1433 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1434 &applesmc_dmi_data[4]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001435 { applesmc_dmi_match, "Apple iMac 9,1", {
1436 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
1437 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
1438 &applesmc_dmi_data[17]},
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001439 { applesmc_dmi_match, "Apple iMac 8", {
1440 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1441 DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
1442 &applesmc_dmi_data[13]},
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001443 { applesmc_dmi_match, "Apple iMac 6", {
1444 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1445 DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
1446 &applesmc_dmi_data[14]},
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001447 { applesmc_dmi_match, "Apple iMac 5", {
1448 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1449 DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
1450 &applesmc_dmi_data[10]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001451 { applesmc_dmi_match, "Apple iMac", {
1452 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1453 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001454 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001455 { .ident = NULL }
1456};
1457
1458static int __init applesmc_init(void)
1459{
1460 int ret;
1461 int count;
1462 int i;
1463
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001464 if (!dmi_check_system(applesmc_whitelist)) {
1465 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1466 ret = -ENODEV;
1467 goto out;
1468 }
1469
1470 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1471 "applesmc")) {
1472 ret = -ENXIO;
1473 goto out;
1474 }
1475
1476 ret = platform_driver_register(&applesmc_driver);
1477 if (ret)
1478 goto out_region;
1479
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001480 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1481 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001482 if (IS_ERR(pdev)) {
1483 ret = PTR_ERR(pdev);
1484 goto out_driver;
1485 }
1486
Nicolas Boichatfa744192007-05-23 13:58:13 -07001487 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001488 if (ret)
1489 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001490
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001491 /* Create key enumeration sysfs files */
1492 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1493 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001494 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001495
1496 /* create fan files */
1497 count = applesmc_get_fan_count();
Henrik Rydberg0559a532010-05-11 09:17:47 +02001498 if (count < 0)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001499 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
Henrik Rydberg0559a532010-05-11 09:17:47 +02001500 else
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001501 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1502
Henrik Rydberg0559a532010-05-11 09:17:47 +02001503 if (count > 4) {
1504 count = 4;
1505 printk(KERN_WARNING "applesmc: More than 4 fans found,"
1506 " but at most 4 fans are supported"
1507 " by the driver.\n");
1508 }
1509
1510 while (fans_handled < count) {
1511 ret = sysfs_create_group(&pdev->dev.kobj,
1512 &fan_attribute_groups[fans_handled]);
1513 if (ret)
1514 goto out_fans;
1515 fans_handled++;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001516 }
1517
1518 for (i = 0;
1519 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1520 i++) {
1521 if (temperature_attributes[i] == NULL) {
1522 printk(KERN_ERR "applesmc: More temperature sensors "
1523 "in temperature_sensors_sets (at least %i)"
1524 "than available sysfs files in "
1525 "temperature_attributes (%i), please report "
1526 "this bug.\n", i, i-1);
1527 goto out_temperature;
1528 }
1529 ret = sysfs_create_file(&pdev->dev.kobj,
1530 temperature_attributes[i]);
1531 if (ret)
1532 goto out_temperature;
1533 }
1534
1535 if (applesmc_accelerometer) {
1536 ret = applesmc_create_accelerometer();
1537 if (ret)
1538 goto out_temperature;
1539 }
1540
1541 if (applesmc_light) {
1542 /* Add light sensor file */
1543 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1544 if (ret)
1545 goto out_accelerometer;
1546
1547 /* Create the workqueue */
1548 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1549 if (!applesmc_led_wq) {
1550 ret = -ENOMEM;
1551 goto out_light_sysfs;
1552 }
1553
1554 /* register as a led device */
1555 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1556 if (ret < 0)
1557 goto out_light_wq;
1558 }
1559
Tony Jones1beeffe2007-08-20 13:46:20 -07001560 hwmon_dev = hwmon_device_register(&pdev->dev);
1561 if (IS_ERR(hwmon_dev)) {
1562 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001563 goto out_light_ledclass;
1564 }
1565
1566 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1567
1568 return 0;
1569
1570out_light_ledclass:
1571 if (applesmc_light)
1572 led_classdev_unregister(&applesmc_backlight);
1573out_light_wq:
1574 if (applesmc_light)
1575 destroy_workqueue(applesmc_led_wq);
1576out_light_sysfs:
1577 if (applesmc_light)
1578 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1579out_accelerometer:
1580 if (applesmc_accelerometer)
1581 applesmc_release_accelerometer();
1582out_temperature:
1583 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
Henrik Rydberg0559a532010-05-11 09:17:47 +02001584out_fans:
1585 while (fans_handled)
1586 sysfs_remove_group(&pdev->dev.kobj,
1587 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001588 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001589out_name:
1590 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001591out_device:
1592 platform_device_unregister(pdev);
1593out_driver:
1594 platform_driver_unregister(&applesmc_driver);
1595out_region:
1596 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1597out:
1598 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1599 return ret;
1600}
1601
1602static void __exit applesmc_exit(void)
1603{
Tony Jones1beeffe2007-08-20 13:46:20 -07001604 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001605 if (applesmc_light) {
1606 led_classdev_unregister(&applesmc_backlight);
1607 destroy_workqueue(applesmc_led_wq);
1608 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1609 }
1610 if (applesmc_accelerometer)
1611 applesmc_release_accelerometer();
1612 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
Henrik Rydberg0559a532010-05-11 09:17:47 +02001613 while (fans_handled)
1614 sysfs_remove_group(&pdev->dev.kobj,
1615 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001616 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001617 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001618 platform_device_unregister(pdev);
1619 platform_driver_unregister(&applesmc_driver);
1620 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1621
1622 printk(KERN_INFO "applesmc: driver unloaded.\n");
1623}
1624
1625module_init(applesmc_init);
1626module_exit(applesmc_exit);
1627
1628MODULE_AUTHOR("Nicolas Boichat");
1629MODULE_DESCRIPTION("Apple SMC");
1630MODULE_LICENSE("GPL v2");
Henrik Rydbergdc924ef2008-12-01 13:13:49 -08001631MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);