blob: bc011da79e148249e24a1439e3c4cb55fcd1c7b0 [file] [log] [blame]
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001/*
2 * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature
3 * sensors, fan control, keyboard backlight control) used in Intel-based Apple
4 * computers.
5 *
6 * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
7 *
8 * Based on hdaps.c driver:
9 * Copyright (C) 2005 Robert Love <rml@novell.com>
10 * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
11 *
12 * Fan control based on smcFanControl:
13 * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License v2 as published by the
17 * Free Software Foundation.
18 *
19 * This program is distributed in the hope that it will be useful, but WITHOUT
20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
22 * more details.
23 *
24 * You should have received a copy of the GNU General Public License along with
25 * this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29#include <linux/delay.h>
30#include <linux/platform_device.h>
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040031#include <linux/input-polldev.h>
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070032#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/timer.h>
35#include <linux/dmi.h>
36#include <linux/mutex.h>
37#include <linux/hwmon-sysfs.h>
38#include <asm/io.h>
39#include <linux/leds.h>
40#include <linux/hwmon.h>
41#include <linux/workqueue.h>
42
43/* data port used by Apple SMC */
44#define APPLESMC_DATA_PORT 0x300
45/* command/status port used by Apple SMC */
46#define APPLESMC_CMD_PORT 0x304
47
48#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
49
50#define APPLESMC_MAX_DATA_LENGTH 32
51
Henrik Rydberg8c9398d2008-10-18 20:27:43 -070052#define APPLESMC_MIN_WAIT 0x0040
53#define APPLESMC_MAX_WAIT 0x8000
54
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070055#define APPLESMC_STATUS_MASK 0x0f
56#define APPLESMC_READ_CMD 0x10
57#define APPLESMC_WRITE_CMD 0x11
58#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
59#define APPLESMC_GET_KEY_TYPE_CMD 0x13
60
61#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */
62
Henrik Rydberg8bd1a122008-10-18 20:27:39 -070063#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6-10 bytes) */
64#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6-10 bytes) */
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040065#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070066
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040067#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070068
69#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
70#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
71#define MOTION_SENSOR_Z_KEY "MO_Z" /* r-o sp78 (2 bytes) */
72#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */
73
74#define FANS_COUNT "FNum" /* r-o ui8 */
75#define FANS_MANUAL "FS! " /* r-w ui16 */
76#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
77#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
78#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
79#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
80#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
81#define FAN_POSITION "F0ID" /* r-o char[16] */
82
83/*
84 * Temperature sensors keys (sp78 - 2 bytes).
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070085 */
René Rebe8de57702007-10-16 14:19:20 -070086static const char* temperature_sensors_sets[][36] = {
Martin Szulecki1bed24b2007-07-09 11:41:36 -070087/* Set 0: Macbook Pro */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070088 { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
89 "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080090/* Set 1: Macbook2 set */
91 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
92 "Th0S", "Th1H", NULL },
93/* Set 2: Macbook set */
Martin Szulecki1bed24b2007-07-09 11:41:36 -070094 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
95 "Th1H", "Ts0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080096/* Set 3: Macmini set */
René Rebe8de57702007-10-16 14:19:20 -070097 { "TC0D", "TC0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080098/* Set 4: Mac Pro (2 x Quad-Core) */
René Rebe8de57702007-10-16 14:19:20 -070099 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
100 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
101 "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
102 "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
103 "TM9S", "TN0H", "TS0C", NULL },
Roberto De Ioris9f86f282008-08-15 00:40:30 -0700104/* Set 5: iMac */
105 { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
106 "Tp0C", NULL },
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -0700107/* Set 6: Macbook3 set */
108 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
109 "Th0S", "Th1H", NULL },
Henrik Rydbergf5274c92008-10-18 20:27:40 -0700110/* Set 7: Macbook Air */
111 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
112 "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
Henrik Rydbergd7549902008-10-18 20:27:41 -0700113/* Set 8: Macbook Pro 4,1 (Penryn) */
114 { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
115 "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -0700116/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
117 { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
118 "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700119};
120
121/* List of keys used to read/write fan speeds */
122static const char* fan_speed_keys[] = {
123 FAN_ACTUAL_SPEED,
124 FAN_MIN_SPEED,
125 FAN_MAX_SPEED,
126 FAN_SAFE_SPEED,
127 FAN_TARGET_SPEED
128};
129
130#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
131#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
132
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400133#define APPLESMC_POLL_INTERVAL 50 /* msecs */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700134#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
135#define APPLESMC_INPUT_FLAT 4
136
137#define SENSOR_X 0
138#define SENSOR_Y 1
139#define SENSOR_Z 2
140
141/* Structure to be passed to DMI_MATCH function */
142struct dmi_match_data {
143/* Indicates whether this computer has an accelerometer. */
144 int accelerometer;
145/* Indicates whether this computer has light sensors and keyboard backlight. */
146 int light;
147/* Indicates which temperature sensors set to use. */
148 int temperature_set;
149};
150
151static const int debug;
152static struct platform_device *pdev;
153static s16 rest_x;
154static s16 rest_y;
Tony Jones1beeffe2007-08-20 13:46:20 -0700155static struct device *hwmon_dev;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400156static struct input_polled_dev *applesmc_idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700157
158/* Indicates whether this computer has an accelerometer. */
159static unsigned int applesmc_accelerometer;
160
161/* Indicates whether this computer has light sensors and keyboard backlight. */
162static unsigned int applesmc_light;
163
164/* Indicates which temperature sensors set to use. */
165static unsigned int applesmc_temperature_set;
166
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400167static DEFINE_MUTEX(applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700168
169/*
170 * Last index written to key_at_index sysfs file, and value to use for all other
171 * key_at_index_* sysfs files.
172 */
173static unsigned int key_at_index;
174
175static struct workqueue_struct *applesmc_led_wq;
176
177/*
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700178 * __wait_status - Wait up to 32ms for the status port to get a certain value
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700179 * (masked with 0x0f), returning zero if the value is obtained. Callers must
180 * hold applesmc_lock.
181 */
182static int __wait_status(u8 val)
183{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700184 int us;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700185
186 val = val & APPLESMC_STATUS_MASK;
187
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700188 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
189 udelay(us);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700190 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
191 if (debug)
192 printk(KERN_DEBUG
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700193 "Waited %d us for status %x\n",
194 2 * us - APPLESMC_MIN_WAIT, val);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700195 return 0;
196 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700197 }
198
199 printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
200 val, inb(APPLESMC_CMD_PORT));
201
202 return -EIO;
203}
204
205/*
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700206 * special treatment of command port - on newer macbooks, it seems necessary
207 * to resend the command byte before polling the status again. Callers must
208 * hold applesmc_lock.
209 */
210static int send_command(u8 cmd)
211{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700212 int us;
213 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700214 outb(cmd, APPLESMC_CMD_PORT);
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700215 udelay(us);
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700216 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
217 return 0;
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700218 }
219 printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
220 cmd, inb(APPLESMC_CMD_PORT));
221 return -EIO;
222}
223
224/*
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700225 * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
226 * Returns zero on success or a negative error on failure. Callers must
227 * hold applesmc_lock.
228 */
229static int applesmc_read_key(const char* key, u8* buffer, u8 len)
230{
231 int i;
232
233 if (len > APPLESMC_MAX_DATA_LENGTH) {
234 printk(KERN_ERR "applesmc_read_key: cannot read more than "
235 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
236 return -EINVAL;
237 }
238
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700239 if (send_command(APPLESMC_READ_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700240 return -EIO;
241
242 for (i = 0; i < 4; i++) {
243 outb(key[i], APPLESMC_DATA_PORT);
244 if (__wait_status(0x04))
245 return -EIO;
246 }
247 if (debug)
248 printk(KERN_DEBUG "<%s", key);
249
250 outb(len, APPLESMC_DATA_PORT);
251 if (debug)
252 printk(KERN_DEBUG ">%x", len);
253
254 for (i = 0; i < len; i++) {
255 if (__wait_status(0x05))
256 return -EIO;
257 buffer[i] = inb(APPLESMC_DATA_PORT);
258 if (debug)
259 printk(KERN_DEBUG "<%x", buffer[i]);
260 }
261 if (debug)
262 printk(KERN_DEBUG "\n");
263
264 return 0;
265}
266
267/*
268 * applesmc_write_key - writes len bytes from buffer to a given key.
269 * Returns zero on success or a negative error on failure. Callers must
270 * hold applesmc_lock.
271 */
272static int applesmc_write_key(const char* key, u8* buffer, u8 len)
273{
274 int i;
275
276 if (len > APPLESMC_MAX_DATA_LENGTH) {
277 printk(KERN_ERR "applesmc_write_key: cannot write more than "
278 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
279 return -EINVAL;
280 }
281
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700282 if (send_command(APPLESMC_WRITE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700283 return -EIO;
284
285 for (i = 0; i < 4; i++) {
286 outb(key[i], APPLESMC_DATA_PORT);
287 if (__wait_status(0x04))
288 return -EIO;
289 }
290
291 outb(len, APPLESMC_DATA_PORT);
292
293 for (i = 0; i < len; i++) {
294 if (__wait_status(0x04))
295 return -EIO;
296 outb(buffer[i], APPLESMC_DATA_PORT);
297 }
298
299 return 0;
300}
301
302/*
303 * applesmc_get_key_at_index - get key at index, and put the result in key
304 * (char[6]). Returns zero on success or a negative error on failure. Callers
305 * must hold applesmc_lock.
306 */
307static int applesmc_get_key_at_index(int index, char* key)
308{
309 int i;
310 u8 readkey[4];
311 readkey[0] = index >> 24;
312 readkey[1] = index >> 16;
313 readkey[2] = index >> 8;
314 readkey[3] = index;
315
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700316 if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700317 return -EIO;
318
319 for (i = 0; i < 4; i++) {
320 outb(readkey[i], APPLESMC_DATA_PORT);
321 if (__wait_status(0x04))
322 return -EIO;
323 }
324
325 outb(4, APPLESMC_DATA_PORT);
326
327 for (i = 0; i < 4; i++) {
328 if (__wait_status(0x05))
329 return -EIO;
330 key[i] = inb(APPLESMC_DATA_PORT);
331 }
332 key[4] = 0;
333
334 return 0;
335}
336
337/*
338 * applesmc_get_key_type - get key type, and put the result in type (char[6]).
339 * Returns zero on success or a negative error on failure. Callers must
340 * hold applesmc_lock.
341 */
342static int applesmc_get_key_type(char* key, char* type)
343{
344 int i;
345
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700346 if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700347 return -EIO;
348
349 for (i = 0; i < 4; i++) {
350 outb(key[i], APPLESMC_DATA_PORT);
351 if (__wait_status(0x04))
352 return -EIO;
353 }
354
Henrik Rydberg05224092008-10-18 20:27:35 -0700355 outb(6, APPLESMC_DATA_PORT);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700356
357 for (i = 0; i < 6; i++) {
358 if (__wait_status(0x05))
359 return -EIO;
360 type[i] = inb(APPLESMC_DATA_PORT);
361 }
362 type[5] = 0;
363
364 return 0;
365}
366
367/*
368 * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
369 * hold applesmc_lock.
370 */
371static int applesmc_read_motion_sensor(int index, s16* value)
372{
373 u8 buffer[2];
374 int ret;
375
376 switch (index) {
377 case SENSOR_X:
378 ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
379 break;
380 case SENSOR_Y:
381 ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
382 break;
383 case SENSOR_Z:
384 ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
385 break;
386 default:
387 ret = -EINVAL;
388 }
389
390 *value = ((s16)buffer[0] << 8) | buffer[1];
391
392 return ret;
393}
394
395/*
396 * applesmc_device_init - initialize the accelerometer. Returns zero on success
397 * and negative error code on failure. Can sleep.
398 */
399static int applesmc_device_init(void)
400{
401 int total, ret = -ENXIO;
402 u8 buffer[2];
403
404 if (!applesmc_accelerometer)
405 return 0;
406
407 mutex_lock(&applesmc_lock);
408
409 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
410 if (debug)
411 printk(KERN_DEBUG "applesmc try %d\n", total);
412 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
413 (buffer[0] != 0x00 || buffer[1] != 0x00)) {
414 if (total == INIT_TIMEOUT_MSECS) {
415 printk(KERN_DEBUG "applesmc: device has"
416 " already been initialized"
417 " (0x%02x, 0x%02x).\n",
418 buffer[0], buffer[1]);
419 } else {
420 printk(KERN_DEBUG "applesmc: device"
421 " successfully initialized"
422 " (0x%02x, 0x%02x).\n",
423 buffer[0], buffer[1]);
424 }
425 ret = 0;
426 goto out;
427 }
428 buffer[0] = 0xe0;
429 buffer[1] = 0x00;
430 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
431 msleep(INIT_WAIT_MSECS);
432 }
433
434 printk(KERN_WARNING "applesmc: failed to init the device\n");
435
436out:
437 mutex_unlock(&applesmc_lock);
438 return ret;
439}
440
441/*
442 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
443 * applesmc_lock.
444 */
445static int applesmc_get_fan_count(void)
446{
447 int ret;
448 u8 buffer[1];
449
450 mutex_lock(&applesmc_lock);
451
452 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
453
454 mutex_unlock(&applesmc_lock);
455 if (ret)
456 return ret;
457 else
458 return buffer[0];
459}
460
461/* Device model stuff */
462static int applesmc_probe(struct platform_device *dev)
463{
464 int ret;
465
466 ret = applesmc_device_init();
467 if (ret)
468 return ret;
469
470 printk(KERN_INFO "applesmc: device successfully initialized.\n");
471 return 0;
472}
473
474static int applesmc_resume(struct platform_device *dev)
475{
476 return applesmc_device_init();
477}
478
479static struct platform_driver applesmc_driver = {
480 .probe = applesmc_probe,
481 .resume = applesmc_resume,
482 .driver = {
483 .name = "applesmc",
484 .owner = THIS_MODULE,
485 },
486};
487
488/*
489 * applesmc_calibrate - Set our "resting" values. Callers must
490 * hold applesmc_lock.
491 */
492static void applesmc_calibrate(void)
493{
494 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
495 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
496 rest_x = -rest_x;
497}
498
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400499static void applesmc_idev_poll(struct input_polled_dev *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700500{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400501 struct input_dev *idev = dev->input;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700502 s16 x, y;
503
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400504 mutex_lock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700505
506 if (applesmc_read_motion_sensor(SENSOR_X, &x))
507 goto out;
508 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
509 goto out;
510
511 x = -x;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400512 input_report_abs(idev, ABS_X, x - rest_x);
513 input_report_abs(idev, ABS_Y, y - rest_y);
514 input_sync(idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700515
516out:
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700517 mutex_unlock(&applesmc_lock);
518}
519
520/* Sysfs Files */
521
Nicolas Boichatfa744192007-05-23 13:58:13 -0700522static ssize_t applesmc_name_show(struct device *dev,
523 struct device_attribute *attr, char *buf)
524{
525 return snprintf(buf, PAGE_SIZE, "applesmc\n");
526}
527
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700528static ssize_t applesmc_position_show(struct device *dev,
529 struct device_attribute *attr, char *buf)
530{
531 int ret;
532 s16 x, y, z;
533
534 mutex_lock(&applesmc_lock);
535
536 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
537 if (ret)
538 goto out;
539 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
540 if (ret)
541 goto out;
542 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
543 if (ret)
544 goto out;
545
546out:
547 mutex_unlock(&applesmc_lock);
548 if (ret)
549 return ret;
550 else
551 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
552}
553
554static ssize_t applesmc_light_show(struct device *dev,
555 struct device_attribute *attr, char *sysfsbuf)
556{
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700557 static int data_length;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700558 int ret;
559 u8 left = 0, right = 0;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700560 u8 buffer[10], query[6];
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700561
562 mutex_lock(&applesmc_lock);
563
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700564 if (!data_length) {
565 ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
566 if (ret)
567 goto out;
568 data_length = clamp_val(query[0], 0, 10);
569 printk(KERN_INFO "applesmc: light sensor data length set to "
570 "%d\n", data_length);
571 }
572
573 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700574 left = buffer[2];
575 if (ret)
576 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700577 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700578 right = buffer[2];
579
580out:
581 mutex_unlock(&applesmc_lock);
582 if (ret)
583 return ret;
584 else
585 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
586}
587
588/* Displays degree Celsius * 1000 */
589static ssize_t applesmc_show_temperature(struct device *dev,
590 struct device_attribute *devattr, char *sysfsbuf)
591{
592 int ret;
593 u8 buffer[2];
594 unsigned int temp;
595 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
596 const char* key =
597 temperature_sensors_sets[applesmc_temperature_set][attr->index];
598
599 mutex_lock(&applesmc_lock);
600
601 ret = applesmc_read_key(key, buffer, 2);
602 temp = buffer[0]*1000;
603 temp += (buffer[1] >> 6) * 250;
604
605 mutex_unlock(&applesmc_lock);
606
607 if (ret)
608 return ret;
609 else
610 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
611}
612
613static ssize_t applesmc_show_fan_speed(struct device *dev,
614 struct device_attribute *attr, char *sysfsbuf)
615{
616 int ret;
617 unsigned int speed = 0;
618 char newkey[5];
619 u8 buffer[2];
620 struct sensor_device_attribute_2 *sensor_attr =
621 to_sensor_dev_attr_2(attr);
622
623 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
624 newkey[1] = '0' + sensor_attr->index;
625 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
626 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
627 newkey[4] = 0;
628
629 mutex_lock(&applesmc_lock);
630
631 ret = applesmc_read_key(newkey, buffer, 2);
632 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
633
634 mutex_unlock(&applesmc_lock);
635 if (ret)
636 return ret;
637 else
638 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
639}
640
641static ssize_t applesmc_store_fan_speed(struct device *dev,
642 struct device_attribute *attr,
643 const char *sysfsbuf, size_t count)
644{
645 int ret;
646 u32 speed;
647 char newkey[5];
648 u8 buffer[2];
649 struct sensor_device_attribute_2 *sensor_attr =
650 to_sensor_dev_attr_2(attr);
651
652 speed = simple_strtoul(sysfsbuf, NULL, 10);
653
654 if (speed > 0x4000) /* Bigger than a 14-bit value */
655 return -EINVAL;
656
657 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
658 newkey[1] = '0' + sensor_attr->index;
659 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
660 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
661 newkey[4] = 0;
662
663 mutex_lock(&applesmc_lock);
664
665 buffer[0] = (speed >> 6) & 0xff;
666 buffer[1] = (speed << 2) & 0xff;
667 ret = applesmc_write_key(newkey, buffer, 2);
668
669 mutex_unlock(&applesmc_lock);
670 if (ret)
671 return ret;
672 else
673 return count;
674}
675
676static ssize_t applesmc_show_fan_manual(struct device *dev,
677 struct device_attribute *devattr, char *sysfsbuf)
678{
679 int ret;
680 u16 manual = 0;
681 u8 buffer[2];
682 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
683
684 mutex_lock(&applesmc_lock);
685
686 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
687 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
688
689 mutex_unlock(&applesmc_lock);
690 if (ret)
691 return ret;
692 else
693 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
694}
695
696static ssize_t applesmc_store_fan_manual(struct device *dev,
697 struct device_attribute *devattr,
698 const char *sysfsbuf, size_t count)
699{
700 int ret;
701 u8 buffer[2];
702 u32 input;
703 u16 val;
704 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
705
706 input = simple_strtoul(sysfsbuf, NULL, 10);
707
708 mutex_lock(&applesmc_lock);
709
710 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
711 val = (buffer[0] << 8 | buffer[1]);
712 if (ret)
713 goto out;
714
715 if (input)
716 val = val | (0x01 << attr->index);
717 else
718 val = val & ~(0x01 << attr->index);
719
720 buffer[0] = (val >> 8) & 0xFF;
721 buffer[1] = val & 0xFF;
722
723 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
724
725out:
726 mutex_unlock(&applesmc_lock);
727 if (ret)
728 return ret;
729 else
730 return count;
731}
732
733static ssize_t applesmc_show_fan_position(struct device *dev,
734 struct device_attribute *attr, char *sysfsbuf)
735{
736 int ret;
737 char newkey[5];
738 u8 buffer[17];
739 struct sensor_device_attribute_2 *sensor_attr =
740 to_sensor_dev_attr_2(attr);
741
742 newkey[0] = FAN_POSITION[0];
743 newkey[1] = '0' + sensor_attr->index;
744 newkey[2] = FAN_POSITION[2];
745 newkey[3] = FAN_POSITION[3];
746 newkey[4] = 0;
747
748 mutex_lock(&applesmc_lock);
749
750 ret = applesmc_read_key(newkey, buffer, 16);
751 buffer[16] = 0;
752
753 mutex_unlock(&applesmc_lock);
754 if (ret)
755 return ret;
756 else
757 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
758}
759
760static ssize_t applesmc_calibrate_show(struct device *dev,
761 struct device_attribute *attr, char *sysfsbuf)
762{
763 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
764}
765
766static ssize_t applesmc_calibrate_store(struct device *dev,
767 struct device_attribute *attr, const char *sysfsbuf, size_t count)
768{
769 mutex_lock(&applesmc_lock);
770 applesmc_calibrate();
771 mutex_unlock(&applesmc_lock);
772
773 return count;
774}
775
776/* Store the next backlight value to be written by the work */
777static unsigned int backlight_value;
778
779static void applesmc_backlight_set(struct work_struct *work)
780{
781 u8 buffer[2];
782
783 mutex_lock(&applesmc_lock);
784 buffer[0] = backlight_value;
785 buffer[1] = 0x00;
786 applesmc_write_key(BACKLIGHT_KEY, buffer, 2);
787 mutex_unlock(&applesmc_lock);
788}
789static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
790
791static void applesmc_brightness_set(struct led_classdev *led_cdev,
792 enum led_brightness value)
793{
794 int ret;
795
796 backlight_value = value;
797 ret = queue_work(applesmc_led_wq, &backlight_work);
798
799 if (debug && (!ret))
800 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
801}
802
803static ssize_t applesmc_key_count_show(struct device *dev,
804 struct device_attribute *attr, char *sysfsbuf)
805{
806 int ret;
807 u8 buffer[4];
808 u32 count;
809
810 mutex_lock(&applesmc_lock);
811
812 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
813 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
814 ((u32)buffer[2]<<8) + buffer[3];
815
816 mutex_unlock(&applesmc_lock);
817 if (ret)
818 return ret;
819 else
820 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
821}
822
823static ssize_t applesmc_key_at_index_read_show(struct device *dev,
824 struct device_attribute *attr, char *sysfsbuf)
825{
826 char key[5];
827 char info[6];
828 int ret;
829
830 mutex_lock(&applesmc_lock);
831
832 ret = applesmc_get_key_at_index(key_at_index, key);
833
834 if (ret || !key[0]) {
835 mutex_unlock(&applesmc_lock);
836
837 return -EINVAL;
838 }
839
840 ret = applesmc_get_key_type(key, info);
841
842 if (ret) {
843 mutex_unlock(&applesmc_lock);
844
845 return ret;
846 }
847
848 /*
849 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
850 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
851 */
852 ret = applesmc_read_key(key, sysfsbuf, info[0]);
853
854 mutex_unlock(&applesmc_lock);
855
856 if (!ret) {
857 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400858 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700859 return ret;
860 }
861}
862
863static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
864 struct device_attribute *attr, char *sysfsbuf)
865{
866 char key[5];
867 char info[6];
868 int ret;
869
870 mutex_lock(&applesmc_lock);
871
872 ret = applesmc_get_key_at_index(key_at_index, key);
873
874 if (ret || !key[0]) {
875 mutex_unlock(&applesmc_lock);
876
877 return -EINVAL;
878 }
879
880 ret = applesmc_get_key_type(key, info);
881
882 mutex_unlock(&applesmc_lock);
883
884 if (!ret)
885 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
886 else
887 return ret;
888}
889
890static ssize_t applesmc_key_at_index_type_show(struct device *dev,
891 struct device_attribute *attr, char *sysfsbuf)
892{
893 char key[5];
894 char info[6];
895 int ret;
896
897 mutex_lock(&applesmc_lock);
898
899 ret = applesmc_get_key_at_index(key_at_index, key);
900
901 if (ret || !key[0]) {
902 mutex_unlock(&applesmc_lock);
903
904 return -EINVAL;
905 }
906
907 ret = applesmc_get_key_type(key, info);
908
909 mutex_unlock(&applesmc_lock);
910
911 if (!ret)
912 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
913 else
914 return ret;
915}
916
917static ssize_t applesmc_key_at_index_name_show(struct device *dev,
918 struct device_attribute *attr, char *sysfsbuf)
919{
920 char key[5];
921 int ret;
922
923 mutex_lock(&applesmc_lock);
924
925 ret = applesmc_get_key_at_index(key_at_index, key);
926
927 mutex_unlock(&applesmc_lock);
928
929 if (!ret && key[0])
930 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
931 else
932 return -EINVAL;
933}
934
935static ssize_t applesmc_key_at_index_show(struct device *dev,
936 struct device_attribute *attr, char *sysfsbuf)
937{
938 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
939}
940
941static ssize_t applesmc_key_at_index_store(struct device *dev,
942 struct device_attribute *attr, const char *sysfsbuf, size_t count)
943{
944 mutex_lock(&applesmc_lock);
945
946 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
947
948 mutex_unlock(&applesmc_lock);
949
950 return count;
951}
952
953static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +0100954 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700955 .default_trigger = "nand-disk",
956 .brightness_set = applesmc_brightness_set,
957};
958
Nicolas Boichatfa744192007-05-23 13:58:13 -0700959static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
960
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700961static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
962static DEVICE_ATTR(calibrate, 0644,
963 applesmc_calibrate_show, applesmc_calibrate_store);
964
965static struct attribute *accelerometer_attributes[] = {
966 &dev_attr_position.attr,
967 &dev_attr_calibrate.attr,
968 NULL
969};
970
971static const struct attribute_group accelerometer_attributes_group =
972 { .attrs = accelerometer_attributes };
973
974static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
975
976static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
977static DEVICE_ATTR(key_at_index, 0644,
978 applesmc_key_at_index_show, applesmc_key_at_index_store);
979static DEVICE_ATTR(key_at_index_name, 0444,
980 applesmc_key_at_index_name_show, NULL);
981static DEVICE_ATTR(key_at_index_type, 0444,
982 applesmc_key_at_index_type_show, NULL);
983static DEVICE_ATTR(key_at_index_data_length, 0444,
984 applesmc_key_at_index_data_length_show, NULL);
985static DEVICE_ATTR(key_at_index_data, 0444,
986 applesmc_key_at_index_read_show, NULL);
987
988static struct attribute *key_enumeration_attributes[] = {
989 &dev_attr_key_count.attr,
990 &dev_attr_key_at_index.attr,
991 &dev_attr_key_at_index_name.attr,
992 &dev_attr_key_at_index_type.attr,
993 &dev_attr_key_at_index_data_length.attr,
994 &dev_attr_key_at_index_data.attr,
995 NULL
996};
997
998static const struct attribute_group key_enumeration_group =
999 { .attrs = key_enumeration_attributes };
1000
1001/*
1002 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1003 * - show actual speed
1004 * - show/store minimum speed
1005 * - show maximum speed
1006 * - show safe speed
1007 * - show/store target speed
1008 * - show/store manual mode
1009 */
1010#define sysfs_fan_speeds_offset(offset) \
1011static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1012 applesmc_show_fan_speed, NULL, 0, offset-1); \
1013\
1014static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1015 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1016\
1017static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1018 applesmc_show_fan_speed, NULL, 2, offset-1); \
1019\
1020static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1021 applesmc_show_fan_speed, NULL, 3, offset-1); \
1022\
1023static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1024 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1025\
1026static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1027 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1028\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001029static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001030 applesmc_show_fan_position, NULL, offset-1); \
1031\
1032static struct attribute *fan##offset##_attributes[] = { \
1033 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1034 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1035 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1036 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1037 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1038 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001039 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001040 NULL \
1041};
1042
1043/*
1044 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001045 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001046 */
1047sysfs_fan_speeds_offset(1);
1048sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001049sysfs_fan_speeds_offset(3);
1050sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001051
1052static const struct attribute_group fan_attribute_groups[] = {
1053 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001054 { .attrs = fan2_attributes },
1055 { .attrs = fan3_attributes },
1056 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001057};
1058
1059/*
1060 * Temperature sensors sysfs entries.
1061 */
1062static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1063 applesmc_show_temperature, NULL, 0);
1064static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1065 applesmc_show_temperature, NULL, 1);
1066static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1067 applesmc_show_temperature, NULL, 2);
1068static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1069 applesmc_show_temperature, NULL, 3);
1070static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1071 applesmc_show_temperature, NULL, 4);
1072static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1073 applesmc_show_temperature, NULL, 5);
1074static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1075 applesmc_show_temperature, NULL, 6);
1076static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1077 applesmc_show_temperature, NULL, 7);
1078static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1079 applesmc_show_temperature, NULL, 8);
1080static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1081 applesmc_show_temperature, NULL, 9);
1082static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1083 applesmc_show_temperature, NULL, 10);
1084static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1085 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001086static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1087 applesmc_show_temperature, NULL, 12);
1088static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1089 applesmc_show_temperature, NULL, 13);
1090static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1091 applesmc_show_temperature, NULL, 14);
1092static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1093 applesmc_show_temperature, NULL, 15);
1094static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1095 applesmc_show_temperature, NULL, 16);
1096static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1097 applesmc_show_temperature, NULL, 17);
1098static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1099 applesmc_show_temperature, NULL, 18);
1100static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1101 applesmc_show_temperature, NULL, 19);
1102static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1103 applesmc_show_temperature, NULL, 20);
1104static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1105 applesmc_show_temperature, NULL, 21);
1106static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1107 applesmc_show_temperature, NULL, 22);
1108static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1109 applesmc_show_temperature, NULL, 23);
1110static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1111 applesmc_show_temperature, NULL, 24);
1112static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1113 applesmc_show_temperature, NULL, 25);
1114static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1115 applesmc_show_temperature, NULL, 26);
1116static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1117 applesmc_show_temperature, NULL, 27);
1118static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1119 applesmc_show_temperature, NULL, 28);
1120static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1121 applesmc_show_temperature, NULL, 29);
1122static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1123 applesmc_show_temperature, NULL, 30);
1124static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1125 applesmc_show_temperature, NULL, 31);
1126static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1127 applesmc_show_temperature, NULL, 32);
1128static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1129 applesmc_show_temperature, NULL, 33);
1130static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1131 applesmc_show_temperature, NULL, 34);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001132
1133static struct attribute *temperature_attributes[] = {
1134 &sensor_dev_attr_temp1_input.dev_attr.attr,
1135 &sensor_dev_attr_temp2_input.dev_attr.attr,
1136 &sensor_dev_attr_temp3_input.dev_attr.attr,
1137 &sensor_dev_attr_temp4_input.dev_attr.attr,
1138 &sensor_dev_attr_temp5_input.dev_attr.attr,
1139 &sensor_dev_attr_temp6_input.dev_attr.attr,
1140 &sensor_dev_attr_temp7_input.dev_attr.attr,
1141 &sensor_dev_attr_temp8_input.dev_attr.attr,
1142 &sensor_dev_attr_temp9_input.dev_attr.attr,
1143 &sensor_dev_attr_temp10_input.dev_attr.attr,
1144 &sensor_dev_attr_temp11_input.dev_attr.attr,
1145 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001146 &sensor_dev_attr_temp13_input.dev_attr.attr,
1147 &sensor_dev_attr_temp14_input.dev_attr.attr,
1148 &sensor_dev_attr_temp15_input.dev_attr.attr,
1149 &sensor_dev_attr_temp16_input.dev_attr.attr,
1150 &sensor_dev_attr_temp17_input.dev_attr.attr,
1151 &sensor_dev_attr_temp18_input.dev_attr.attr,
1152 &sensor_dev_attr_temp19_input.dev_attr.attr,
1153 &sensor_dev_attr_temp20_input.dev_attr.attr,
1154 &sensor_dev_attr_temp21_input.dev_attr.attr,
1155 &sensor_dev_attr_temp22_input.dev_attr.attr,
1156 &sensor_dev_attr_temp23_input.dev_attr.attr,
1157 &sensor_dev_attr_temp24_input.dev_attr.attr,
1158 &sensor_dev_attr_temp25_input.dev_attr.attr,
1159 &sensor_dev_attr_temp26_input.dev_attr.attr,
1160 &sensor_dev_attr_temp27_input.dev_attr.attr,
1161 &sensor_dev_attr_temp28_input.dev_attr.attr,
1162 &sensor_dev_attr_temp29_input.dev_attr.attr,
1163 &sensor_dev_attr_temp30_input.dev_attr.attr,
1164 &sensor_dev_attr_temp31_input.dev_attr.attr,
1165 &sensor_dev_attr_temp32_input.dev_attr.attr,
1166 &sensor_dev_attr_temp33_input.dev_attr.attr,
1167 &sensor_dev_attr_temp34_input.dev_attr.attr,
1168 &sensor_dev_attr_temp35_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001169 NULL
1170};
1171
1172static const struct attribute_group temperature_attributes_group =
1173 { .attrs = temperature_attributes };
1174
1175/* Module stuff */
1176
1177/*
1178 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1179 */
Jeff Garzik18552562007-10-03 15:15:40 -04001180static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001181{
1182 int i = 0;
1183 struct dmi_match_data* dmi_data = id->driver_data;
1184 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1185 applesmc_accelerometer = dmi_data->accelerometer;
1186 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1187 applesmc_accelerometer ? "with" : "without");
1188 applesmc_light = dmi_data->light;
1189 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1190 applesmc_light ? "with" : "without");
1191
1192 applesmc_temperature_set = dmi_data->temperature_set;
1193 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1194 i++;
1195 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1196 return 1;
1197}
1198
1199/* Create accelerometer ressources */
1200static int applesmc_create_accelerometer(void)
1201{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001202 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001203 int ret;
1204
1205 ret = sysfs_create_group(&pdev->dev.kobj,
1206 &accelerometer_attributes_group);
1207 if (ret)
1208 goto out;
1209
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001210 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001211 if (!applesmc_idev) {
1212 ret = -ENOMEM;
1213 goto out_sysfs;
1214 }
1215
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001216 applesmc_idev->poll = applesmc_idev_poll;
1217 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1218
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001219 /* initial calibrate for the input device */
1220 applesmc_calibrate();
1221
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001222 /* initialize the input device */
1223 idev = applesmc_idev->input;
1224 idev->name = "applesmc";
1225 idev->id.bustype = BUS_HOST;
1226 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001227 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001228 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001229 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001230 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001231 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1232
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001233 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001234 if (ret)
1235 goto out_idev;
1236
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001237 return 0;
1238
1239out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001240 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001241
1242out_sysfs:
1243 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1244
1245out:
1246 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1247 return ret;
1248}
1249
1250/* Release all ressources used by the accelerometer */
1251static void applesmc_release_accelerometer(void)
1252{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001253 input_unregister_polled_device(applesmc_idev);
1254 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001255 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1256}
1257
1258static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1259/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1260 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001261/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001262 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001263/* MacBook: accelerometer and temperature set 2 */
1264 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1265/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001266 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001267/* MacPro: temperature set 4 */
1268 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001269/* iMac: temperature set 5 */
1270 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001271/* MacBook3: accelerometer and temperature set 6 */
1272 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001273/* MacBook Air: accelerometer, backlight and temperature set 7 */
1274 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001275/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1276 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001277/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1278 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001279};
1280
1281/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1282 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1283static __initdata struct dmi_system_id applesmc_whitelist[] = {
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001284 { applesmc_dmi_match, "Apple MacBook Air", {
1285 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1286 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001287 &applesmc_dmi_data[7]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001288 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1289 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1290 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1291 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001292 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1293 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1294 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1295 &applesmc_dmi_data[9]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001296 { applesmc_dmi_match, "Apple MacBook Pro", {
1297 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1298 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001299 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001300 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001301 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001302 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001303 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001304 { applesmc_dmi_match, "Apple MacBook (v3)", {
1305 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1306 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001307 &applesmc_dmi_data[6]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001308 { applesmc_dmi_match, "Apple MacBook", {
1309 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1310 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001311 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001312 { applesmc_dmi_match, "Apple Macmini", {
1313 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1314 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001315 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001316 { applesmc_dmi_match, "Apple MacPro2", {
1317 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1318 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001319 &applesmc_dmi_data[4]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001320 { applesmc_dmi_match, "Apple iMac", {
1321 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1322 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001323 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001324 { .ident = NULL }
1325};
1326
1327static int __init applesmc_init(void)
1328{
1329 int ret;
1330 int count;
1331 int i;
1332
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001333 if (!dmi_check_system(applesmc_whitelist)) {
1334 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1335 ret = -ENODEV;
1336 goto out;
1337 }
1338
1339 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1340 "applesmc")) {
1341 ret = -ENXIO;
1342 goto out;
1343 }
1344
1345 ret = platform_driver_register(&applesmc_driver);
1346 if (ret)
1347 goto out_region;
1348
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001349 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1350 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001351 if (IS_ERR(pdev)) {
1352 ret = PTR_ERR(pdev);
1353 goto out_driver;
1354 }
1355
Nicolas Boichatfa744192007-05-23 13:58:13 -07001356 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001357 if (ret)
1358 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001359
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001360 /* Create key enumeration sysfs files */
1361 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1362 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001363 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001364
1365 /* create fan files */
1366 count = applesmc_get_fan_count();
1367 if (count < 0) {
1368 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
1369 } else {
1370 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1371
1372 switch (count) {
1373 default:
René Rebe8de57702007-10-16 14:19:20 -07001374 printk(KERN_WARNING "applesmc: More than 4 fans found,"
1375 " but at most 4 fans are supported"
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001376 " by the driver.\n");
René Rebe8de57702007-10-16 14:19:20 -07001377 case 4:
1378 ret = sysfs_create_group(&pdev->dev.kobj,
1379 &fan_attribute_groups[3]);
1380 if (ret)
1381 goto out_key_enumeration;
1382 case 3:
1383 ret = sysfs_create_group(&pdev->dev.kobj,
1384 &fan_attribute_groups[2]);
1385 if (ret)
1386 goto out_key_enumeration;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001387 case 2:
1388 ret = sysfs_create_group(&pdev->dev.kobj,
1389 &fan_attribute_groups[1]);
1390 if (ret)
1391 goto out_key_enumeration;
1392 case 1:
1393 ret = sysfs_create_group(&pdev->dev.kobj,
1394 &fan_attribute_groups[0]);
1395 if (ret)
1396 goto out_fan_1;
1397 case 0:
1398 ;
1399 }
1400 }
1401
1402 for (i = 0;
1403 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1404 i++) {
1405 if (temperature_attributes[i] == NULL) {
1406 printk(KERN_ERR "applesmc: More temperature sensors "
1407 "in temperature_sensors_sets (at least %i)"
1408 "than available sysfs files in "
1409 "temperature_attributes (%i), please report "
1410 "this bug.\n", i, i-1);
1411 goto out_temperature;
1412 }
1413 ret = sysfs_create_file(&pdev->dev.kobj,
1414 temperature_attributes[i]);
1415 if (ret)
1416 goto out_temperature;
1417 }
1418
1419 if (applesmc_accelerometer) {
1420 ret = applesmc_create_accelerometer();
1421 if (ret)
1422 goto out_temperature;
1423 }
1424
1425 if (applesmc_light) {
1426 /* Add light sensor file */
1427 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1428 if (ret)
1429 goto out_accelerometer;
1430
1431 /* Create the workqueue */
1432 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1433 if (!applesmc_led_wq) {
1434 ret = -ENOMEM;
1435 goto out_light_sysfs;
1436 }
1437
1438 /* register as a led device */
1439 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1440 if (ret < 0)
1441 goto out_light_wq;
1442 }
1443
Tony Jones1beeffe2007-08-20 13:46:20 -07001444 hwmon_dev = hwmon_device_register(&pdev->dev);
1445 if (IS_ERR(hwmon_dev)) {
1446 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001447 goto out_light_ledclass;
1448 }
1449
1450 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1451
1452 return 0;
1453
1454out_light_ledclass:
1455 if (applesmc_light)
1456 led_classdev_unregister(&applesmc_backlight);
1457out_light_wq:
1458 if (applesmc_light)
1459 destroy_workqueue(applesmc_led_wq);
1460out_light_sysfs:
1461 if (applesmc_light)
1462 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1463out_accelerometer:
1464 if (applesmc_accelerometer)
1465 applesmc_release_accelerometer();
1466out_temperature:
1467 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1468 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1469out_fan_1:
1470 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1471out_key_enumeration:
1472 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001473out_name:
1474 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001475out_device:
1476 platform_device_unregister(pdev);
1477out_driver:
1478 platform_driver_unregister(&applesmc_driver);
1479out_region:
1480 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1481out:
1482 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1483 return ret;
1484}
1485
1486static void __exit applesmc_exit(void)
1487{
Tony Jones1beeffe2007-08-20 13:46:20 -07001488 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001489 if (applesmc_light) {
1490 led_classdev_unregister(&applesmc_backlight);
1491 destroy_workqueue(applesmc_led_wq);
1492 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1493 }
1494 if (applesmc_accelerometer)
1495 applesmc_release_accelerometer();
1496 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
1497 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
1498 sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
1499 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001500 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001501 platform_device_unregister(pdev);
1502 platform_driver_unregister(&applesmc_driver);
1503 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1504
1505 printk(KERN_INFO "applesmc: driver unloaded.\n");
1506}
1507
1508module_init(applesmc_init);
1509module_exit(applesmc_exit);
1510
1511MODULE_AUTHOR("Nicolas Boichat");
1512MODULE_DESCRIPTION("Apple SMC");
1513MODULE_LICENSE("GPL v2");