blob: 7ea6a8f66056827970f31f13a3a3cedd135db1fd [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 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700145};
146
147/* List of keys used to read/write fan speeds */
148static const char* fan_speed_keys[] = {
149 FAN_ACTUAL_SPEED,
150 FAN_MIN_SPEED,
151 FAN_MAX_SPEED,
152 FAN_SAFE_SPEED,
153 FAN_TARGET_SPEED
154};
155
156#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
157#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
158
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400159#define APPLESMC_POLL_INTERVAL 50 /* msecs */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700160#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
161#define APPLESMC_INPUT_FLAT 4
162
163#define SENSOR_X 0
164#define SENSOR_Y 1
165#define SENSOR_Z 2
166
167/* Structure to be passed to DMI_MATCH function */
168struct dmi_match_data {
169/* Indicates whether this computer has an accelerometer. */
170 int accelerometer;
171/* Indicates whether this computer has light sensors and keyboard backlight. */
172 int light;
173/* Indicates which temperature sensors set to use. */
174 int temperature_set;
175};
176
177static const int debug;
178static struct platform_device *pdev;
179static s16 rest_x;
180static s16 rest_y;
Henrik Rydberga976f152009-09-21 17:04:50 -0700181static u8 backlight_state[2];
182
Tony Jones1beeffe2007-08-20 13:46:20 -0700183static struct device *hwmon_dev;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400184static struct input_polled_dev *applesmc_idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700185
186/* Indicates whether this computer has an accelerometer. */
187static unsigned int applesmc_accelerometer;
188
189/* Indicates whether this computer has light sensors and keyboard backlight. */
190static unsigned int applesmc_light;
191
192/* Indicates which temperature sensors set to use. */
193static unsigned int applesmc_temperature_set;
194
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400195static DEFINE_MUTEX(applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700196
197/*
198 * Last index written to key_at_index sysfs file, and value to use for all other
199 * key_at_index_* sysfs files.
200 */
201static unsigned int key_at_index;
202
203static struct workqueue_struct *applesmc_led_wq;
204
205/*
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700206 * __wait_status - Wait up to 32ms for the status port to get a certain value
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700207 * (masked with 0x0f), returning zero if the value is obtained. Callers must
208 * hold applesmc_lock.
209 */
210static int __wait_status(u8 val)
211{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700212 int us;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700213
214 val = val & APPLESMC_STATUS_MASK;
215
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700216 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
217 udelay(us);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700218 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
219 if (debug)
220 printk(KERN_DEBUG
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700221 "Waited %d us for status %x\n",
222 2 * us - APPLESMC_MIN_WAIT, val);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700223 return 0;
224 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700225 }
226
227 printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
228 val, inb(APPLESMC_CMD_PORT));
229
230 return -EIO;
231}
232
233/*
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700234 * special treatment of command port - on newer macbooks, it seems necessary
235 * to resend the command byte before polling the status again. Callers must
236 * hold applesmc_lock.
237 */
238static int send_command(u8 cmd)
239{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700240 int us;
241 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700242 outb(cmd, APPLESMC_CMD_PORT);
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700243 udelay(us);
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700244 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
245 return 0;
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700246 }
247 printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
248 cmd, inb(APPLESMC_CMD_PORT));
249 return -EIO;
250}
251
252/*
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700253 * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
254 * Returns zero on success or a negative error on failure. Callers must
255 * hold applesmc_lock.
256 */
257static int applesmc_read_key(const char* key, u8* buffer, u8 len)
258{
259 int i;
260
261 if (len > APPLESMC_MAX_DATA_LENGTH) {
262 printk(KERN_ERR "applesmc_read_key: cannot read more than "
263 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
264 return -EINVAL;
265 }
266
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700267 if (send_command(APPLESMC_READ_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700268 return -EIO;
269
270 for (i = 0; i < 4; i++) {
271 outb(key[i], APPLESMC_DATA_PORT);
272 if (__wait_status(0x04))
273 return -EIO;
274 }
275 if (debug)
276 printk(KERN_DEBUG "<%s", key);
277
278 outb(len, APPLESMC_DATA_PORT);
279 if (debug)
280 printk(KERN_DEBUG ">%x", len);
281
282 for (i = 0; i < len; i++) {
283 if (__wait_status(0x05))
284 return -EIO;
285 buffer[i] = inb(APPLESMC_DATA_PORT);
286 if (debug)
287 printk(KERN_DEBUG "<%x", buffer[i]);
288 }
289 if (debug)
290 printk(KERN_DEBUG "\n");
291
292 return 0;
293}
294
295/*
296 * applesmc_write_key - writes len bytes from buffer to a given key.
297 * Returns zero on success or a negative error on failure. Callers must
298 * hold applesmc_lock.
299 */
300static int applesmc_write_key(const char* key, u8* buffer, u8 len)
301{
302 int i;
303
304 if (len > APPLESMC_MAX_DATA_LENGTH) {
305 printk(KERN_ERR "applesmc_write_key: cannot write more than "
306 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
307 return -EINVAL;
308 }
309
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700310 if (send_command(APPLESMC_WRITE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700311 return -EIO;
312
313 for (i = 0; i < 4; i++) {
314 outb(key[i], APPLESMC_DATA_PORT);
315 if (__wait_status(0x04))
316 return -EIO;
317 }
318
319 outb(len, APPLESMC_DATA_PORT);
320
321 for (i = 0; i < len; i++) {
322 if (__wait_status(0x04))
323 return -EIO;
324 outb(buffer[i], APPLESMC_DATA_PORT);
325 }
326
327 return 0;
328}
329
330/*
331 * applesmc_get_key_at_index - get key at index, and put the result in key
332 * (char[6]). Returns zero on success or a negative error on failure. Callers
333 * must hold applesmc_lock.
334 */
335static int applesmc_get_key_at_index(int index, char* key)
336{
337 int i;
338 u8 readkey[4];
339 readkey[0] = index >> 24;
340 readkey[1] = index >> 16;
341 readkey[2] = index >> 8;
342 readkey[3] = index;
343
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700344 if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700345 return -EIO;
346
347 for (i = 0; i < 4; i++) {
348 outb(readkey[i], APPLESMC_DATA_PORT);
349 if (__wait_status(0x04))
350 return -EIO;
351 }
352
353 outb(4, APPLESMC_DATA_PORT);
354
355 for (i = 0; i < 4; i++) {
356 if (__wait_status(0x05))
357 return -EIO;
358 key[i] = inb(APPLESMC_DATA_PORT);
359 }
360 key[4] = 0;
361
362 return 0;
363}
364
365/*
366 * applesmc_get_key_type - get key type, and put the result in type (char[6]).
367 * Returns zero on success or a negative error on failure. Callers must
368 * hold applesmc_lock.
369 */
370static int applesmc_get_key_type(char* key, char* type)
371{
372 int i;
373
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700374 if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700375 return -EIO;
376
377 for (i = 0; i < 4; i++) {
378 outb(key[i], APPLESMC_DATA_PORT);
379 if (__wait_status(0x04))
380 return -EIO;
381 }
382
Henrik Rydberg05224092008-10-18 20:27:35 -0700383 outb(6, APPLESMC_DATA_PORT);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700384
385 for (i = 0; i < 6; i++) {
386 if (__wait_status(0x05))
387 return -EIO;
388 type[i] = inb(APPLESMC_DATA_PORT);
389 }
390 type[5] = 0;
391
392 return 0;
393}
394
395/*
396 * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
397 * hold applesmc_lock.
398 */
399static int applesmc_read_motion_sensor(int index, s16* value)
400{
401 u8 buffer[2];
402 int ret;
403
404 switch (index) {
405 case SENSOR_X:
406 ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
407 break;
408 case SENSOR_Y:
409 ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
410 break;
411 case SENSOR_Z:
412 ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
413 break;
414 default:
415 ret = -EINVAL;
416 }
417
418 *value = ((s16)buffer[0] << 8) | buffer[1];
419
420 return ret;
421}
422
423/*
424 * applesmc_device_init - initialize the accelerometer. Returns zero on success
425 * and negative error code on failure. Can sleep.
426 */
427static int applesmc_device_init(void)
428{
429 int total, ret = -ENXIO;
430 u8 buffer[2];
431
432 if (!applesmc_accelerometer)
433 return 0;
434
435 mutex_lock(&applesmc_lock);
436
437 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
438 if (debug)
439 printk(KERN_DEBUG "applesmc try %d\n", total);
440 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
441 (buffer[0] != 0x00 || buffer[1] != 0x00)) {
442 if (total == INIT_TIMEOUT_MSECS) {
443 printk(KERN_DEBUG "applesmc: device has"
444 " already been initialized"
445 " (0x%02x, 0x%02x).\n",
446 buffer[0], buffer[1]);
447 } else {
448 printk(KERN_DEBUG "applesmc: device"
449 " successfully initialized"
450 " (0x%02x, 0x%02x).\n",
451 buffer[0], buffer[1]);
452 }
453 ret = 0;
454 goto out;
455 }
456 buffer[0] = 0xe0;
457 buffer[1] = 0x00;
458 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
459 msleep(INIT_WAIT_MSECS);
460 }
461
462 printk(KERN_WARNING "applesmc: failed to init the device\n");
463
464out:
465 mutex_unlock(&applesmc_lock);
466 return ret;
467}
468
469/*
470 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
471 * applesmc_lock.
472 */
473static int applesmc_get_fan_count(void)
474{
475 int ret;
476 u8 buffer[1];
477
478 mutex_lock(&applesmc_lock);
479
480 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
481
482 mutex_unlock(&applesmc_lock);
483 if (ret)
484 return ret;
485 else
486 return buffer[0];
487}
488
489/* Device model stuff */
490static int applesmc_probe(struct platform_device *dev)
491{
492 int ret;
493
494 ret = applesmc_device_init();
495 if (ret)
496 return ret;
497
498 printk(KERN_INFO "applesmc: device successfully initialized.\n");
499 return 0;
500}
501
Henrik Rydberga976f152009-09-21 17:04:50 -0700502/* Synchronize device with memorized backlight state */
503static int applesmc_pm_resume(struct device *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700504{
Henrik Rydberga976f152009-09-21 17:04:50 -0700505 mutex_lock(&applesmc_lock);
506 if (applesmc_light)
507 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
508 mutex_unlock(&applesmc_lock);
509 return 0;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700510}
511
Henrik Rydberga976f152009-09-21 17:04:50 -0700512/* Reinitialize device on resume from hibernation */
513static int applesmc_pm_restore(struct device *dev)
514{
515 int ret = applesmc_device_init();
516 if (ret)
517 return ret;
518 return applesmc_pm_resume(dev);
519}
520
521static struct dev_pm_ops applesmc_pm_ops = {
522 .resume = applesmc_pm_resume,
523 .restore = applesmc_pm_restore,
524};
525
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700526static struct platform_driver applesmc_driver = {
527 .probe = applesmc_probe,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700528 .driver = {
529 .name = "applesmc",
530 .owner = THIS_MODULE,
Henrik Rydberga976f152009-09-21 17:04:50 -0700531 .pm = &applesmc_pm_ops,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700532 },
533};
534
535/*
536 * applesmc_calibrate - Set our "resting" values. Callers must
537 * hold applesmc_lock.
538 */
539static void applesmc_calibrate(void)
540{
541 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
542 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
543 rest_x = -rest_x;
544}
545
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400546static void applesmc_idev_poll(struct input_polled_dev *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700547{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400548 struct input_dev *idev = dev->input;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700549 s16 x, y;
550
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400551 mutex_lock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700552
553 if (applesmc_read_motion_sensor(SENSOR_X, &x))
554 goto out;
555 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
556 goto out;
557
558 x = -x;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400559 input_report_abs(idev, ABS_X, x - rest_x);
560 input_report_abs(idev, ABS_Y, y - rest_y);
561 input_sync(idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700562
563out:
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700564 mutex_unlock(&applesmc_lock);
565}
566
567/* Sysfs Files */
568
Nicolas Boichatfa744192007-05-23 13:58:13 -0700569static ssize_t applesmc_name_show(struct device *dev,
570 struct device_attribute *attr, char *buf)
571{
572 return snprintf(buf, PAGE_SIZE, "applesmc\n");
573}
574
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700575static ssize_t applesmc_position_show(struct device *dev,
576 struct device_attribute *attr, char *buf)
577{
578 int ret;
579 s16 x, y, z;
580
581 mutex_lock(&applesmc_lock);
582
583 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
584 if (ret)
585 goto out;
586 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
587 if (ret)
588 goto out;
589 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
590 if (ret)
591 goto out;
592
593out:
594 mutex_unlock(&applesmc_lock);
595 if (ret)
596 return ret;
597 else
598 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
599}
600
601static ssize_t applesmc_light_show(struct device *dev,
602 struct device_attribute *attr, char *sysfsbuf)
603{
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700604 static int data_length;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700605 int ret;
606 u8 left = 0, right = 0;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700607 u8 buffer[10], query[6];
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700608
609 mutex_lock(&applesmc_lock);
610
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700611 if (!data_length) {
612 ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
613 if (ret)
614 goto out;
615 data_length = clamp_val(query[0], 0, 10);
616 printk(KERN_INFO "applesmc: light sensor data length set to "
617 "%d\n", data_length);
618 }
619
620 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Alex Murrayc3d63622009-01-15 13:51:08 -0800621 /* newer macbooks report a single 10-bit bigendian value */
622 if (data_length == 10) {
623 left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
624 goto out;
625 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700626 left = buffer[2];
627 if (ret)
628 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700629 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700630 right = buffer[2];
631
632out:
633 mutex_unlock(&applesmc_lock);
634 if (ret)
635 return ret;
636 else
637 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
638}
639
640/* Displays degree Celsius * 1000 */
641static ssize_t applesmc_show_temperature(struct device *dev,
642 struct device_attribute *devattr, char *sysfsbuf)
643{
644 int ret;
645 u8 buffer[2];
646 unsigned int temp;
647 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
648 const char* key =
649 temperature_sensors_sets[applesmc_temperature_set][attr->index];
650
651 mutex_lock(&applesmc_lock);
652
653 ret = applesmc_read_key(key, buffer, 2);
654 temp = buffer[0]*1000;
655 temp += (buffer[1] >> 6) * 250;
656
657 mutex_unlock(&applesmc_lock);
658
659 if (ret)
660 return ret;
661 else
662 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
663}
664
665static ssize_t applesmc_show_fan_speed(struct device *dev,
666 struct device_attribute *attr, char *sysfsbuf)
667{
668 int ret;
669 unsigned int speed = 0;
670 char newkey[5];
671 u8 buffer[2];
672 struct sensor_device_attribute_2 *sensor_attr =
673 to_sensor_dev_attr_2(attr);
674
675 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
676 newkey[1] = '0' + sensor_attr->index;
677 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
678 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
679 newkey[4] = 0;
680
681 mutex_lock(&applesmc_lock);
682
683 ret = applesmc_read_key(newkey, buffer, 2);
684 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
685
686 mutex_unlock(&applesmc_lock);
687 if (ret)
688 return ret;
689 else
690 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
691}
692
693static ssize_t applesmc_store_fan_speed(struct device *dev,
694 struct device_attribute *attr,
695 const char *sysfsbuf, size_t count)
696{
697 int ret;
698 u32 speed;
699 char newkey[5];
700 u8 buffer[2];
701 struct sensor_device_attribute_2 *sensor_attr =
702 to_sensor_dev_attr_2(attr);
703
704 speed = simple_strtoul(sysfsbuf, NULL, 10);
705
706 if (speed > 0x4000) /* Bigger than a 14-bit value */
707 return -EINVAL;
708
709 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
710 newkey[1] = '0' + sensor_attr->index;
711 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
712 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
713 newkey[4] = 0;
714
715 mutex_lock(&applesmc_lock);
716
717 buffer[0] = (speed >> 6) & 0xff;
718 buffer[1] = (speed << 2) & 0xff;
719 ret = applesmc_write_key(newkey, buffer, 2);
720
721 mutex_unlock(&applesmc_lock);
722 if (ret)
723 return ret;
724 else
725 return count;
726}
727
728static ssize_t applesmc_show_fan_manual(struct device *dev,
729 struct device_attribute *devattr, char *sysfsbuf)
730{
731 int ret;
732 u16 manual = 0;
733 u8 buffer[2];
734 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
735
736 mutex_lock(&applesmc_lock);
737
738 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
739 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
740
741 mutex_unlock(&applesmc_lock);
742 if (ret)
743 return ret;
744 else
745 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
746}
747
748static ssize_t applesmc_store_fan_manual(struct device *dev,
749 struct device_attribute *devattr,
750 const char *sysfsbuf, size_t count)
751{
752 int ret;
753 u8 buffer[2];
754 u32 input;
755 u16 val;
756 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
757
758 input = simple_strtoul(sysfsbuf, NULL, 10);
759
760 mutex_lock(&applesmc_lock);
761
762 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
763 val = (buffer[0] << 8 | buffer[1]);
764 if (ret)
765 goto out;
766
767 if (input)
768 val = val | (0x01 << attr->index);
769 else
770 val = val & ~(0x01 << attr->index);
771
772 buffer[0] = (val >> 8) & 0xFF;
773 buffer[1] = val & 0xFF;
774
775 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
776
777out:
778 mutex_unlock(&applesmc_lock);
779 if (ret)
780 return ret;
781 else
782 return count;
783}
784
785static ssize_t applesmc_show_fan_position(struct device *dev,
786 struct device_attribute *attr, char *sysfsbuf)
787{
788 int ret;
789 char newkey[5];
790 u8 buffer[17];
791 struct sensor_device_attribute_2 *sensor_attr =
792 to_sensor_dev_attr_2(attr);
793
794 newkey[0] = FAN_POSITION[0];
795 newkey[1] = '0' + sensor_attr->index;
796 newkey[2] = FAN_POSITION[2];
797 newkey[3] = FAN_POSITION[3];
798 newkey[4] = 0;
799
800 mutex_lock(&applesmc_lock);
801
802 ret = applesmc_read_key(newkey, buffer, 16);
803 buffer[16] = 0;
804
805 mutex_unlock(&applesmc_lock);
806 if (ret)
807 return ret;
808 else
809 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
810}
811
812static ssize_t applesmc_calibrate_show(struct device *dev,
813 struct device_attribute *attr, char *sysfsbuf)
814{
815 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
816}
817
818static ssize_t applesmc_calibrate_store(struct device *dev,
819 struct device_attribute *attr, const char *sysfsbuf, size_t count)
820{
821 mutex_lock(&applesmc_lock);
822 applesmc_calibrate();
823 mutex_unlock(&applesmc_lock);
824
825 return count;
826}
827
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700828static void applesmc_backlight_set(struct work_struct *work)
829{
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700830 mutex_lock(&applesmc_lock);
Henrik Rydberga976f152009-09-21 17:04:50 -0700831 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700832 mutex_unlock(&applesmc_lock);
833}
834static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
835
836static void applesmc_brightness_set(struct led_classdev *led_cdev,
837 enum led_brightness value)
838{
839 int ret;
840
Henrik Rydberga976f152009-09-21 17:04:50 -0700841 backlight_state[0] = value;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700842 ret = queue_work(applesmc_led_wq, &backlight_work);
843
844 if (debug && (!ret))
845 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
846}
847
848static ssize_t applesmc_key_count_show(struct device *dev,
849 struct device_attribute *attr, char *sysfsbuf)
850{
851 int ret;
852 u8 buffer[4];
853 u32 count;
854
855 mutex_lock(&applesmc_lock);
856
857 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
858 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
859 ((u32)buffer[2]<<8) + buffer[3];
860
861 mutex_unlock(&applesmc_lock);
862 if (ret)
863 return ret;
864 else
865 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
866}
867
868static ssize_t applesmc_key_at_index_read_show(struct device *dev,
869 struct device_attribute *attr, char *sysfsbuf)
870{
871 char key[5];
872 char info[6];
873 int ret;
874
875 mutex_lock(&applesmc_lock);
876
877 ret = applesmc_get_key_at_index(key_at_index, key);
878
879 if (ret || !key[0]) {
880 mutex_unlock(&applesmc_lock);
881
882 return -EINVAL;
883 }
884
885 ret = applesmc_get_key_type(key, info);
886
887 if (ret) {
888 mutex_unlock(&applesmc_lock);
889
890 return ret;
891 }
892
893 /*
894 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
895 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
896 */
897 ret = applesmc_read_key(key, sysfsbuf, info[0]);
898
899 mutex_unlock(&applesmc_lock);
900
901 if (!ret) {
902 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400903 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700904 return ret;
905 }
906}
907
908static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
909 struct device_attribute *attr, char *sysfsbuf)
910{
911 char key[5];
912 char info[6];
913 int ret;
914
915 mutex_lock(&applesmc_lock);
916
917 ret = applesmc_get_key_at_index(key_at_index, key);
918
919 if (ret || !key[0]) {
920 mutex_unlock(&applesmc_lock);
921
922 return -EINVAL;
923 }
924
925 ret = applesmc_get_key_type(key, info);
926
927 mutex_unlock(&applesmc_lock);
928
929 if (!ret)
930 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
931 else
932 return ret;
933}
934
935static ssize_t applesmc_key_at_index_type_show(struct device *dev,
936 struct device_attribute *attr, char *sysfsbuf)
937{
938 char key[5];
939 char info[6];
940 int ret;
941
942 mutex_lock(&applesmc_lock);
943
944 ret = applesmc_get_key_at_index(key_at_index, key);
945
946 if (ret || !key[0]) {
947 mutex_unlock(&applesmc_lock);
948
949 return -EINVAL;
950 }
951
952 ret = applesmc_get_key_type(key, info);
953
954 mutex_unlock(&applesmc_lock);
955
956 if (!ret)
957 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
958 else
959 return ret;
960}
961
962static ssize_t applesmc_key_at_index_name_show(struct device *dev,
963 struct device_attribute *attr, char *sysfsbuf)
964{
965 char key[5];
966 int ret;
967
968 mutex_lock(&applesmc_lock);
969
970 ret = applesmc_get_key_at_index(key_at_index, key);
971
972 mutex_unlock(&applesmc_lock);
973
974 if (!ret && key[0])
975 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
976 else
977 return -EINVAL;
978}
979
980static ssize_t applesmc_key_at_index_show(struct device *dev,
981 struct device_attribute *attr, char *sysfsbuf)
982{
983 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
984}
985
986static ssize_t applesmc_key_at_index_store(struct device *dev,
987 struct device_attribute *attr, const char *sysfsbuf, size_t count)
988{
989 mutex_lock(&applesmc_lock);
990
991 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
992
993 mutex_unlock(&applesmc_lock);
994
995 return count;
996}
997
998static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +0100999 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001000 .default_trigger = "nand-disk",
1001 .brightness_set = applesmc_brightness_set,
1002};
1003
Nicolas Boichatfa744192007-05-23 13:58:13 -07001004static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
1005
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001006static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
1007static DEVICE_ATTR(calibrate, 0644,
1008 applesmc_calibrate_show, applesmc_calibrate_store);
1009
1010static struct attribute *accelerometer_attributes[] = {
1011 &dev_attr_position.attr,
1012 &dev_attr_calibrate.attr,
1013 NULL
1014};
1015
1016static const struct attribute_group accelerometer_attributes_group =
1017 { .attrs = accelerometer_attributes };
1018
1019static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
1020
1021static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
1022static DEVICE_ATTR(key_at_index, 0644,
1023 applesmc_key_at_index_show, applesmc_key_at_index_store);
1024static DEVICE_ATTR(key_at_index_name, 0444,
1025 applesmc_key_at_index_name_show, NULL);
1026static DEVICE_ATTR(key_at_index_type, 0444,
1027 applesmc_key_at_index_type_show, NULL);
1028static DEVICE_ATTR(key_at_index_data_length, 0444,
1029 applesmc_key_at_index_data_length_show, NULL);
1030static DEVICE_ATTR(key_at_index_data, 0444,
1031 applesmc_key_at_index_read_show, NULL);
1032
1033static struct attribute *key_enumeration_attributes[] = {
1034 &dev_attr_key_count.attr,
1035 &dev_attr_key_at_index.attr,
1036 &dev_attr_key_at_index_name.attr,
1037 &dev_attr_key_at_index_type.attr,
1038 &dev_attr_key_at_index_data_length.attr,
1039 &dev_attr_key_at_index_data.attr,
1040 NULL
1041};
1042
1043static const struct attribute_group key_enumeration_group =
1044 { .attrs = key_enumeration_attributes };
1045
1046/*
1047 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1048 * - show actual speed
1049 * - show/store minimum speed
1050 * - show maximum speed
1051 * - show safe speed
1052 * - show/store target speed
1053 * - show/store manual mode
1054 */
1055#define sysfs_fan_speeds_offset(offset) \
1056static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1057 applesmc_show_fan_speed, NULL, 0, offset-1); \
1058\
1059static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1060 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1061\
1062static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1063 applesmc_show_fan_speed, NULL, 2, offset-1); \
1064\
1065static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1066 applesmc_show_fan_speed, NULL, 3, offset-1); \
1067\
1068static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1069 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1070\
1071static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1072 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1073\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001074static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001075 applesmc_show_fan_position, NULL, offset-1); \
1076\
1077static struct attribute *fan##offset##_attributes[] = { \
1078 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1079 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1080 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1081 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1082 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1083 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001084 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001085 NULL \
1086};
1087
1088/*
1089 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001090 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001091 */
1092sysfs_fan_speeds_offset(1);
1093sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001094sysfs_fan_speeds_offset(3);
1095sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001096
1097static const struct attribute_group fan_attribute_groups[] = {
1098 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001099 { .attrs = fan2_attributes },
1100 { .attrs = fan3_attributes },
1101 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001102};
1103
1104/*
1105 * Temperature sensors sysfs entries.
1106 */
1107static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1108 applesmc_show_temperature, NULL, 0);
1109static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1110 applesmc_show_temperature, NULL, 1);
1111static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1112 applesmc_show_temperature, NULL, 2);
1113static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1114 applesmc_show_temperature, NULL, 3);
1115static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1116 applesmc_show_temperature, NULL, 4);
1117static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1118 applesmc_show_temperature, NULL, 5);
1119static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1120 applesmc_show_temperature, NULL, 6);
1121static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1122 applesmc_show_temperature, NULL, 7);
1123static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1124 applesmc_show_temperature, NULL, 8);
1125static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1126 applesmc_show_temperature, NULL, 9);
1127static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1128 applesmc_show_temperature, NULL, 10);
1129static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1130 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001131static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1132 applesmc_show_temperature, NULL, 12);
1133static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1134 applesmc_show_temperature, NULL, 13);
1135static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1136 applesmc_show_temperature, NULL, 14);
1137static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1138 applesmc_show_temperature, NULL, 15);
1139static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1140 applesmc_show_temperature, NULL, 16);
1141static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1142 applesmc_show_temperature, NULL, 17);
1143static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1144 applesmc_show_temperature, NULL, 18);
1145static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1146 applesmc_show_temperature, NULL, 19);
1147static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1148 applesmc_show_temperature, NULL, 20);
1149static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1150 applesmc_show_temperature, NULL, 21);
1151static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1152 applesmc_show_temperature, NULL, 22);
1153static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1154 applesmc_show_temperature, NULL, 23);
1155static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1156 applesmc_show_temperature, NULL, 24);
1157static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1158 applesmc_show_temperature, NULL, 25);
1159static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1160 applesmc_show_temperature, NULL, 26);
1161static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1162 applesmc_show_temperature, NULL, 27);
1163static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1164 applesmc_show_temperature, NULL, 28);
1165static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1166 applesmc_show_temperature, NULL, 29);
1167static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1168 applesmc_show_temperature, NULL, 30);
1169static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1170 applesmc_show_temperature, NULL, 31);
1171static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1172 applesmc_show_temperature, NULL, 32);
1173static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1174 applesmc_show_temperature, NULL, 33);
1175static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1176 applesmc_show_temperature, NULL, 34);
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001177static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
1178 applesmc_show_temperature, NULL, 35);
1179static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
1180 applesmc_show_temperature, NULL, 36);
1181static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
1182 applesmc_show_temperature, NULL, 37);
1183static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
1184 applesmc_show_temperature, NULL, 38);
1185static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
1186 applesmc_show_temperature, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001187
1188static struct attribute *temperature_attributes[] = {
1189 &sensor_dev_attr_temp1_input.dev_attr.attr,
1190 &sensor_dev_attr_temp2_input.dev_attr.attr,
1191 &sensor_dev_attr_temp3_input.dev_attr.attr,
1192 &sensor_dev_attr_temp4_input.dev_attr.attr,
1193 &sensor_dev_attr_temp5_input.dev_attr.attr,
1194 &sensor_dev_attr_temp6_input.dev_attr.attr,
1195 &sensor_dev_attr_temp7_input.dev_attr.attr,
1196 &sensor_dev_attr_temp8_input.dev_attr.attr,
1197 &sensor_dev_attr_temp9_input.dev_attr.attr,
1198 &sensor_dev_attr_temp10_input.dev_attr.attr,
1199 &sensor_dev_attr_temp11_input.dev_attr.attr,
1200 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001201 &sensor_dev_attr_temp13_input.dev_attr.attr,
1202 &sensor_dev_attr_temp14_input.dev_attr.attr,
1203 &sensor_dev_attr_temp15_input.dev_attr.attr,
1204 &sensor_dev_attr_temp16_input.dev_attr.attr,
1205 &sensor_dev_attr_temp17_input.dev_attr.attr,
1206 &sensor_dev_attr_temp18_input.dev_attr.attr,
1207 &sensor_dev_attr_temp19_input.dev_attr.attr,
1208 &sensor_dev_attr_temp20_input.dev_attr.attr,
1209 &sensor_dev_attr_temp21_input.dev_attr.attr,
1210 &sensor_dev_attr_temp22_input.dev_attr.attr,
1211 &sensor_dev_attr_temp23_input.dev_attr.attr,
1212 &sensor_dev_attr_temp24_input.dev_attr.attr,
1213 &sensor_dev_attr_temp25_input.dev_attr.attr,
1214 &sensor_dev_attr_temp26_input.dev_attr.attr,
1215 &sensor_dev_attr_temp27_input.dev_attr.attr,
1216 &sensor_dev_attr_temp28_input.dev_attr.attr,
1217 &sensor_dev_attr_temp29_input.dev_attr.attr,
1218 &sensor_dev_attr_temp30_input.dev_attr.attr,
1219 &sensor_dev_attr_temp31_input.dev_attr.attr,
1220 &sensor_dev_attr_temp32_input.dev_attr.attr,
1221 &sensor_dev_attr_temp33_input.dev_attr.attr,
1222 &sensor_dev_attr_temp34_input.dev_attr.attr,
1223 &sensor_dev_attr_temp35_input.dev_attr.attr,
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001224 &sensor_dev_attr_temp36_input.dev_attr.attr,
1225 &sensor_dev_attr_temp37_input.dev_attr.attr,
1226 &sensor_dev_attr_temp38_input.dev_attr.attr,
1227 &sensor_dev_attr_temp39_input.dev_attr.attr,
1228 &sensor_dev_attr_temp40_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001229 NULL
1230};
1231
1232static const struct attribute_group temperature_attributes_group =
1233 { .attrs = temperature_attributes };
1234
1235/* Module stuff */
1236
1237/*
1238 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1239 */
Jeff Garzik18552562007-10-03 15:15:40 -04001240static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001241{
1242 int i = 0;
1243 struct dmi_match_data* dmi_data = id->driver_data;
1244 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1245 applesmc_accelerometer = dmi_data->accelerometer;
1246 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1247 applesmc_accelerometer ? "with" : "without");
1248 applesmc_light = dmi_data->light;
1249 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1250 applesmc_light ? "with" : "without");
1251
1252 applesmc_temperature_set = dmi_data->temperature_set;
1253 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1254 i++;
1255 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1256 return 1;
1257}
1258
1259/* Create accelerometer ressources */
1260static int applesmc_create_accelerometer(void)
1261{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001262 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001263 int ret;
1264
1265 ret = sysfs_create_group(&pdev->dev.kobj,
1266 &accelerometer_attributes_group);
1267 if (ret)
1268 goto out;
1269
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001270 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001271 if (!applesmc_idev) {
1272 ret = -ENOMEM;
1273 goto out_sysfs;
1274 }
1275
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001276 applesmc_idev->poll = applesmc_idev_poll;
1277 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1278
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001279 /* initial calibrate for the input device */
1280 applesmc_calibrate();
1281
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001282 /* initialize the input device */
1283 idev = applesmc_idev->input;
1284 idev->name = "applesmc";
1285 idev->id.bustype = BUS_HOST;
1286 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001287 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001288 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001289 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001290 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001291 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1292
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001293 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001294 if (ret)
1295 goto out_idev;
1296
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001297 return 0;
1298
1299out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001300 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001301
1302out_sysfs:
1303 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1304
1305out:
1306 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1307 return ret;
1308}
1309
1310/* Release all ressources used by the accelerometer */
1311static void applesmc_release_accelerometer(void)
1312{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001313 input_unregister_polled_device(applesmc_idev);
1314 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001315 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1316}
1317
1318static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1319/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1320 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001321/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001322 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001323/* MacBook: accelerometer and temperature set 2 */
1324 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1325/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001326 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001327/* MacPro: temperature set 4 */
1328 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001329/* iMac: temperature set 5 */
1330 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Henrik Rydberg468cc032008-11-12 13:24:58 -08001331/* MacBook3, MacBook4: accelerometer and temperature set 6 */
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001332 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001333/* MacBook Air: accelerometer, backlight and temperature set 7 */
1334 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001335/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1336 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001337/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1338 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001339/* iMac 5: light sensor only, temperature set 10 */
1340 { .accelerometer = 0, .light = 0, .temperature_set = 10 },
Henrik Rydberg181209a2008-11-06 12:53:20 -08001341/* MacBook 5: accelerometer, backlight and temperature set 11 */
1342 { .accelerometer = 1, .light = 1, .temperature_set = 11 },
Henrik Rydberga6660322008-11-06 12:53:21 -08001343/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
1344 { .accelerometer = 1, .light = 1, .temperature_set = 12 },
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001345/* iMac 8: light sensor only, temperature set 13 */
1346 { .accelerometer = 0, .light = 0, .temperature_set = 13 },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001347/* iMac 6: light sensor only, temperature set 14 */
1348 { .accelerometer = 0, .light = 0, .temperature_set = 14 },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001349/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
1350 { .accelerometer = 1, .light = 1, .temperature_set = 15 },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001351/* MacPro3,1: temperature set 16 */
1352 { .accelerometer = 0, .light = 0, .temperature_set = 16 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001353};
1354
1355/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1356 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1357static __initdata struct dmi_system_id applesmc_whitelist[] = {
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001358 { applesmc_dmi_match, "Apple MacBook Air 2", {
1359 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1360 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
1361 &applesmc_dmi_data[15]},
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001362 { applesmc_dmi_match, "Apple MacBook Air", {
1363 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1364 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001365 &applesmc_dmi_data[7]},
Henrik Rydberga6660322008-11-06 12:53:21 -08001366 { applesmc_dmi_match, "Apple MacBook Pro 5", {
1367 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1368 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
1369 &applesmc_dmi_data[12]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001370 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1371 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1372 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1373 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001374 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1375 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1376 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1377 &applesmc_dmi_data[9]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001378 { applesmc_dmi_match, "Apple MacBook Pro", {
1379 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1380 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001381 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001382 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001383 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001384 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001385 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001386 { applesmc_dmi_match, "Apple MacBook (v3)", {
1387 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1388 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001389 &applesmc_dmi_data[6]},
Henrik Rydberg468cc032008-11-12 13:24:58 -08001390 { applesmc_dmi_match, "Apple MacBook 4", {
1391 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1392 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
1393 &applesmc_dmi_data[6]},
Henrik Rydberg181209a2008-11-06 12:53:20 -08001394 { applesmc_dmi_match, "Apple MacBook 5", {
1395 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1396 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
1397 &applesmc_dmi_data[11]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001398 { applesmc_dmi_match, "Apple MacBook", {
1399 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1400 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001401 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001402 { applesmc_dmi_match, "Apple Macmini", {
1403 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1404 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001405 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001406 { applesmc_dmi_match, "Apple MacPro2", {
1407 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1408 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001409 &applesmc_dmi_data[4]},
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001410 { applesmc_dmi_match, "Apple MacPro3", {
1411 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1412 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
1413 &applesmc_dmi_data[16]},
Henrik Rydberg45a3a362008-11-19 15:36:42 -08001414 { applesmc_dmi_match, "Apple MacPro", {
1415 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1416 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1417 &applesmc_dmi_data[4]},
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001418 { applesmc_dmi_match, "Apple iMac 8", {
1419 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1420 DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
1421 &applesmc_dmi_data[13]},
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001422 { applesmc_dmi_match, "Apple iMac 6", {
1423 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1424 DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
1425 &applesmc_dmi_data[14]},
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001426 { applesmc_dmi_match, "Apple iMac 5", {
1427 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1428 DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
1429 &applesmc_dmi_data[10]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001430 { applesmc_dmi_match, "Apple iMac", {
1431 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1432 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001433 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001434 { .ident = NULL }
1435};
1436
1437static int __init applesmc_init(void)
1438{
1439 int ret;
1440 int count;
1441 int i;
1442
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001443 if (!dmi_check_system(applesmc_whitelist)) {
1444 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1445 ret = -ENODEV;
1446 goto out;
1447 }
1448
1449 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1450 "applesmc")) {
1451 ret = -ENXIO;
1452 goto out;
1453 }
1454
1455 ret = platform_driver_register(&applesmc_driver);
1456 if (ret)
1457 goto out_region;
1458
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001459 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1460 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001461 if (IS_ERR(pdev)) {
1462 ret = PTR_ERR(pdev);
1463 goto out_driver;
1464 }
1465
Nicolas Boichatfa744192007-05-23 13:58:13 -07001466 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001467 if (ret)
1468 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001469
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001470 /* Create key enumeration sysfs files */
1471 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1472 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001473 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001474
1475 /* create fan files */
1476 count = applesmc_get_fan_count();
1477 if (count < 0) {
1478 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
1479 } else {
1480 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1481
1482 switch (count) {
1483 default:
René Rebe8de57702007-10-16 14:19:20 -07001484 printk(KERN_WARNING "applesmc: More than 4 fans found,"
1485 " but at most 4 fans are supported"
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001486 " by the driver.\n");
René Rebe8de57702007-10-16 14:19:20 -07001487 case 4:
1488 ret = sysfs_create_group(&pdev->dev.kobj,
1489 &fan_attribute_groups[3]);
1490 if (ret)
1491 goto out_key_enumeration;
1492 case 3:
1493 ret = sysfs_create_group(&pdev->dev.kobj,
1494 &fan_attribute_groups[2]);
1495 if (ret)
1496 goto out_key_enumeration;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001497 case 2:
1498 ret = sysfs_create_group(&pdev->dev.kobj,
1499 &fan_attribute_groups[1]);
1500 if (ret)
1501 goto out_key_enumeration;
1502 case 1:
1503 ret = sysfs_create_group(&pdev->dev.kobj,
1504 &fan_attribute_groups[0]);
1505 if (ret)
1506 goto out_fan_1;
1507 case 0:
1508 ;
1509 }
1510 }
1511
1512 for (i = 0;
1513 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1514 i++) {
1515 if (temperature_attributes[i] == NULL) {
1516 printk(KERN_ERR "applesmc: More temperature sensors "
1517 "in temperature_sensors_sets (at least %i)"
1518 "than available sysfs files in "
1519 "temperature_attributes (%i), please report "
1520 "this bug.\n", i, i-1);
1521 goto out_temperature;
1522 }
1523 ret = sysfs_create_file(&pdev->dev.kobj,
1524 temperature_attributes[i]);
1525 if (ret)
1526 goto out_temperature;
1527 }
1528
1529 if (applesmc_accelerometer) {
1530 ret = applesmc_create_accelerometer();
1531 if (ret)
1532 goto out_temperature;
1533 }
1534
1535 if (applesmc_light) {
1536 /* Add light sensor file */
1537 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1538 if (ret)
1539 goto out_accelerometer;
1540
1541 /* Create the workqueue */
1542 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1543 if (!applesmc_led_wq) {
1544 ret = -ENOMEM;
1545 goto out_light_sysfs;
1546 }
1547
1548 /* register as a led device */
1549 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1550 if (ret < 0)
1551 goto out_light_wq;
1552 }
1553
Tony Jones1beeffe2007-08-20 13:46:20 -07001554 hwmon_dev = hwmon_device_register(&pdev->dev);
1555 if (IS_ERR(hwmon_dev)) {
1556 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001557 goto out_light_ledclass;
1558 }
1559
1560 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1561
1562 return 0;
1563
1564out_light_ledclass:
1565 if (applesmc_light)
1566 led_classdev_unregister(&applesmc_backlight);
1567out_light_wq:
1568 if (applesmc_light)
1569 destroy_workqueue(applesmc_led_wq);
1570out_light_sysfs:
1571 if (applesmc_light)
1572 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1573out_accelerometer:
1574 if (applesmc_accelerometer)
1575 applesmc_release_accelerometer();
1576out_temperature:
1577 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1578 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1579out_fan_1:
1580 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1581out_key_enumeration:
1582 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001583out_name:
1584 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001585out_device:
1586 platform_device_unregister(pdev);
1587out_driver:
1588 platform_driver_unregister(&applesmc_driver);
1589out_region:
1590 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1591out:
1592 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1593 return ret;
1594}
1595
1596static void __exit applesmc_exit(void)
1597{
Tony Jones1beeffe2007-08-20 13:46:20 -07001598 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001599 if (applesmc_light) {
1600 led_classdev_unregister(&applesmc_backlight);
1601 destroy_workqueue(applesmc_led_wq);
1602 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1603 }
1604 if (applesmc_accelerometer)
1605 applesmc_release_accelerometer();
1606 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1607 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1608 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1609 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001610 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001611 platform_device_unregister(pdev);
1612 platform_driver_unregister(&applesmc_driver);
1613 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1614
1615 printk(KERN_INFO "applesmc: driver unloaded.\n");
1616}
1617
1618module_init(applesmc_init);
1619module_exit(applesmc_exit);
1620
1621MODULE_AUTHOR("Nicolas Boichat");
1622MODULE_DESCRIPTION("Apple SMC");
1623MODULE_LICENSE("GPL v2");
Henrik Rydbergdc924ef2008-12-01 13:13:49 -08001624MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);