blob: d616174807a133e30e2007b81387f636bcd42da2 [file] [log] [blame]
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001/*
2 * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature
3 * sensors, fan control, keyboard backlight control) used in Intel-based Apple
4 * computers.
5 *
6 * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
7 *
8 * Based on hdaps.c driver:
9 * Copyright (C) 2005 Robert Love <rml@novell.com>
10 * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
11 *
12 * Fan control based on smcFanControl:
13 * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
14 *
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License v2 as published by the
17 * Free Software Foundation.
18 *
19 * This program is distributed in the hope that it will be useful, but WITHOUT
20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
22 * more details.
23 *
24 * You should have received a copy of the GNU General Public License along with
25 * this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29#include <linux/delay.h>
30#include <linux/platform_device.h>
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040031#include <linux/input-polldev.h>
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070032#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/timer.h>
35#include <linux/dmi.h>
36#include <linux/mutex.h>
37#include <linux/hwmon-sysfs.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020038#include <linux/io.h>
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070039#include <linux/leds.h>
40#include <linux/hwmon.h>
41#include <linux/workqueue.h>
42
43/* data port used by Apple SMC */
44#define APPLESMC_DATA_PORT 0x300
45/* command/status port used by Apple SMC */
46#define APPLESMC_CMD_PORT 0x304
47
48#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
49
50#define APPLESMC_MAX_DATA_LENGTH 32
51
Henrik Rydberg8c9398d2008-10-18 20:27:43 -070052#define APPLESMC_MIN_WAIT 0x0040
53#define APPLESMC_MAX_WAIT 0x8000
54
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070055#define APPLESMC_STATUS_MASK 0x0f
56#define APPLESMC_READ_CMD 0x10
57#define APPLESMC_WRITE_CMD 0x11
58#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
59#define APPLESMC_GET_KEY_TYPE_CMD 0x13
60
61#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */
62
Henrik Rydberg8bd1a122008-10-18 20:27:39 -070063#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6-10 bytes) */
64#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6-10 bytes) */
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040065#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070066
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040067#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070068
69#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
70#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
71#define MOTION_SENSOR_Z_KEY "MO_Z" /* r-o sp78 (2 bytes) */
72#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */
73
74#define FANS_COUNT "FNum" /* r-o ui8 */
75#define FANS_MANUAL "FS! " /* r-w ui16 */
76#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
77#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
78#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
79#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
80#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
81#define FAN_POSITION "F0ID" /* r-o char[16] */
82
83/*
84 * Temperature sensors keys (sp78 - 2 bytes).
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070085 */
Bharath Rameshfb9f88e2009-01-29 14:25:24 -080086static const char *temperature_sensors_sets[][41] = {
Martin Szulecki1bed24b2007-07-09 11:41:36 -070087/* Set 0: Macbook Pro */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070088 { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
89 "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080090/* Set 1: Macbook2 set */
91 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
92 "Th0S", "Th1H", NULL },
93/* Set 2: Macbook set */
Martin Szulecki1bed24b2007-07-09 11:41:36 -070094 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
95 "Th1H", "Ts0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080096/* Set 3: Macmini set */
René Rebe8de57702007-10-16 14:19:20 -070097 { "TC0D", "TC0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080098/* Set 4: Mac Pro (2 x Quad-Core) */
René Rebe8de57702007-10-16 14:19:20 -070099 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
100 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
101 "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
102 "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
103 "TM9S", "TN0H", "TS0C", NULL },
Roberto De Ioris9f86f282008-08-15 00:40:30 -0700104/* Set 5: iMac */
105 { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
106 "Tp0C", NULL },
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -0700107/* Set 6: Macbook3 set */
108 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
109 "Th0S", "Th1H", NULL },
Henrik Rydbergf5274c92008-10-18 20:27:40 -0700110/* Set 7: Macbook Air */
111 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
112 "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
Henrik Rydbergd7549902008-10-18 20:27:41 -0700113/* Set 8: Macbook Pro 4,1 (Penryn) */
114 { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
115 "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -0700116/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
117 { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
118 "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -0800119/* Set 10: iMac 5,1 */
120 { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL },
Henrik Rydberg181209a12008-11-06 12:53:20 -0800121/* Set 11: Macbook 5,1 */
122 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P",
123 "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL },
Henrik Rydberga6660322008-11-06 12:53:21 -0800124/* Set 12: Macbook Pro 5,1 */
125 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
126 "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0",
127 "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL },
Henrik Rydbergeefc4882008-11-06 12:53:22 -0800128/* Set 13: iMac 8,1 */
129 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
130 "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -0800131/* Set 14: iMac 6,1 */
132 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
133 "TO0P", "Tp0P", NULL },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -0800134/* Set 15: MacBook Air 2,1 */
135 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0",
136 "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P",
137 "Ts0S", NULL },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -0800138/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */
139 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
140 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P",
141 "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P",
142 "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S",
143 "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S",
144 NULL },
Justin P. Mattocke1741712010-04-14 16:14:10 +0200145/* Set 17: iMac 9,1 */
146 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TH0P", "TL0P",
147 "TN0D", "TN0H", "TN0P", "TO0P", "Tm0P", "Tp0P", NULL },
148/* Set 18: MacBook Pro 2,2 */
149 { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
150 "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +0200151/* Set 19: Macbook Pro 5,3 */
152 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
153 "TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H",
154 "Tm0P", "Ts0P", "Ts0S", NULL },
155/* Set 20: MacBook Pro 5,4 */
156 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D",
157 "TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL },
Bernhard Froemel872bad52010-05-27 19:58:52 +0200158/* Set 21: MacBook Pro 6,2 */
159 { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D",
160 "TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P",
161 "Ts0P", "Ts0S", NULL },
Henrik Rydberg405eaa12010-05-27 19:58:53 +0200162/* Set 22: MacBook Pro 7,1 */
163 { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
164 "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
Edgar Hucek132af032010-11-09 15:15:01 +0000165/* Set 23: MacBook Air 3,1 */
166 { "TB0T", "TB1T", "TB2T", "TC0D", "TC0E", "TC0P", "TC1E", "TCZ3",
167 "TCZ4", "TCZ5", "TG0E", "TG1E", "TG2E", "TGZ3", "TGZ4", "TGZ5",
168 "TH0F", "TH0O", "TM0P" },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700169};
170
171/* List of keys used to read/write fan speeds */
172static const char* fan_speed_keys[] = {
173 FAN_ACTUAL_SPEED,
174 FAN_MIN_SPEED,
175 FAN_MAX_SPEED,
176 FAN_SAFE_SPEED,
177 FAN_TARGET_SPEED
178};
179
180#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
181#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
182
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400183#define APPLESMC_POLL_INTERVAL 50 /* msecs */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700184#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
185#define APPLESMC_INPUT_FLAT 4
186
187#define SENSOR_X 0
188#define SENSOR_Y 1
189#define SENSOR_Z 2
190
191/* Structure to be passed to DMI_MATCH function */
192struct dmi_match_data {
193/* Indicates whether this computer has an accelerometer. */
194 int accelerometer;
195/* Indicates whether this computer has light sensors and keyboard backlight. */
196 int light;
197/* Indicates which temperature sensors set to use. */
198 int temperature_set;
199};
200
201static const int debug;
202static struct platform_device *pdev;
203static s16 rest_x;
204static s16 rest_y;
Henrik Rydberga976f152009-09-21 17:04:50 -0700205static u8 backlight_state[2];
206
Tony Jones1beeffe2007-08-20 13:46:20 -0700207static struct device *hwmon_dev;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400208static struct input_polled_dev *applesmc_idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700209
210/* Indicates whether this computer has an accelerometer. */
211static unsigned int applesmc_accelerometer;
212
213/* Indicates whether this computer has light sensors and keyboard backlight. */
214static unsigned int applesmc_light;
215
Henrik Rydberg0559a532010-05-11 09:17:47 +0200216/* The number of fans handled by the driver */
217static unsigned int fans_handled;
218
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700219/* Indicates which temperature sensors set to use. */
220static unsigned int applesmc_temperature_set;
221
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400222static DEFINE_MUTEX(applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700223
224/*
225 * Last index written to key_at_index sysfs file, and value to use for all other
226 * key_at_index_* sysfs files.
227 */
228static unsigned int key_at_index;
229
230static struct workqueue_struct *applesmc_led_wq;
231
232/*
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700233 * __wait_status - Wait up to 32ms for the status port to get a certain value
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700234 * (masked with 0x0f), returning zero if the value is obtained. Callers must
235 * hold applesmc_lock.
236 */
237static int __wait_status(u8 val)
238{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700239 int us;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700240
241 val = val & APPLESMC_STATUS_MASK;
242
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700243 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
244 udelay(us);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700245 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
246 if (debug)
247 printk(KERN_DEBUG
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700248 "Waited %d us for status %x\n",
249 2 * us - APPLESMC_MIN_WAIT, val);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700250 return 0;
251 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700252 }
253
254 printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
255 val, inb(APPLESMC_CMD_PORT));
256
257 return -EIO;
258}
259
260/*
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700261 * special treatment of command port - on newer macbooks, it seems necessary
262 * to resend the command byte before polling the status again. Callers must
263 * hold applesmc_lock.
264 */
265static int send_command(u8 cmd)
266{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700267 int us;
268 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700269 outb(cmd, APPLESMC_CMD_PORT);
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700270 udelay(us);
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700271 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
272 return 0;
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700273 }
274 printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
275 cmd, inb(APPLESMC_CMD_PORT));
276 return -EIO;
277}
278
279/*
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700280 * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
281 * Returns zero on success or a negative error on failure. Callers must
282 * hold applesmc_lock.
283 */
284static int applesmc_read_key(const char* key, u8* buffer, u8 len)
285{
286 int i;
287
288 if (len > APPLESMC_MAX_DATA_LENGTH) {
289 printk(KERN_ERR "applesmc_read_key: cannot read more than "
290 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
291 return -EINVAL;
292 }
293
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700294 if (send_command(APPLESMC_READ_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700295 return -EIO;
296
297 for (i = 0; i < 4; i++) {
298 outb(key[i], APPLESMC_DATA_PORT);
299 if (__wait_status(0x04))
300 return -EIO;
301 }
302 if (debug)
303 printk(KERN_DEBUG "<%s", key);
304
305 outb(len, APPLESMC_DATA_PORT);
306 if (debug)
307 printk(KERN_DEBUG ">%x", len);
308
309 for (i = 0; i < len; i++) {
310 if (__wait_status(0x05))
311 return -EIO;
312 buffer[i] = inb(APPLESMC_DATA_PORT);
313 if (debug)
314 printk(KERN_DEBUG "<%x", buffer[i]);
315 }
316 if (debug)
317 printk(KERN_DEBUG "\n");
318
319 return 0;
320}
321
322/*
323 * applesmc_write_key - writes len bytes from buffer to a given key.
324 * Returns zero on success or a negative error on failure. Callers must
325 * hold applesmc_lock.
326 */
327static int applesmc_write_key(const char* key, u8* buffer, u8 len)
328{
329 int i;
330
331 if (len > APPLESMC_MAX_DATA_LENGTH) {
332 printk(KERN_ERR "applesmc_write_key: cannot write more than "
333 "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
334 return -EINVAL;
335 }
336
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700337 if (send_command(APPLESMC_WRITE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700338 return -EIO;
339
340 for (i = 0; i < 4; i++) {
341 outb(key[i], APPLESMC_DATA_PORT);
342 if (__wait_status(0x04))
343 return -EIO;
344 }
345
346 outb(len, APPLESMC_DATA_PORT);
347
348 for (i = 0; i < len; i++) {
349 if (__wait_status(0x04))
350 return -EIO;
351 outb(buffer[i], APPLESMC_DATA_PORT);
352 }
353
354 return 0;
355}
356
357/*
358 * applesmc_get_key_at_index - get key at index, and put the result in key
359 * (char[6]). Returns zero on success or a negative error on failure. Callers
360 * must hold applesmc_lock.
361 */
362static int applesmc_get_key_at_index(int index, char* key)
363{
364 int i;
365 u8 readkey[4];
366 readkey[0] = index >> 24;
367 readkey[1] = index >> 16;
368 readkey[2] = index >> 8;
369 readkey[3] = index;
370
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700371 if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700372 return -EIO;
373
374 for (i = 0; i < 4; i++) {
375 outb(readkey[i], APPLESMC_DATA_PORT);
376 if (__wait_status(0x04))
377 return -EIO;
378 }
379
380 outb(4, APPLESMC_DATA_PORT);
381
382 for (i = 0; i < 4; i++) {
383 if (__wait_status(0x05))
384 return -EIO;
385 key[i] = inb(APPLESMC_DATA_PORT);
386 }
387 key[4] = 0;
388
389 return 0;
390}
391
392/*
393 * applesmc_get_key_type - get key type, and put the result in type (char[6]).
394 * Returns zero on success or a negative error on failure. Callers must
395 * hold applesmc_lock.
396 */
397static int applesmc_get_key_type(char* key, char* type)
398{
399 int i;
400
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700401 if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700402 return -EIO;
403
404 for (i = 0; i < 4; i++) {
405 outb(key[i], APPLESMC_DATA_PORT);
406 if (__wait_status(0x04))
407 return -EIO;
408 }
409
Henrik Rydberg05224092008-10-18 20:27:35 -0700410 outb(6, APPLESMC_DATA_PORT);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700411
412 for (i = 0; i < 6; i++) {
413 if (__wait_status(0x05))
414 return -EIO;
415 type[i] = inb(APPLESMC_DATA_PORT);
416 }
417 type[5] = 0;
418
419 return 0;
420}
421
422/*
423 * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
424 * hold applesmc_lock.
425 */
426static int applesmc_read_motion_sensor(int index, s16* value)
427{
428 u8 buffer[2];
429 int ret;
430
431 switch (index) {
432 case SENSOR_X:
433 ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
434 break;
435 case SENSOR_Y:
436 ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
437 break;
438 case SENSOR_Z:
439 ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
440 break;
441 default:
442 ret = -EINVAL;
443 }
444
445 *value = ((s16)buffer[0] << 8) | buffer[1];
446
447 return ret;
448}
449
450/*
451 * applesmc_device_init - initialize the accelerometer. Returns zero on success
452 * and negative error code on failure. Can sleep.
453 */
454static int applesmc_device_init(void)
455{
456 int total, ret = -ENXIO;
457 u8 buffer[2];
458
459 if (!applesmc_accelerometer)
460 return 0;
461
462 mutex_lock(&applesmc_lock);
463
464 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
465 if (debug)
466 printk(KERN_DEBUG "applesmc try %d\n", total);
467 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
468 (buffer[0] != 0x00 || buffer[1] != 0x00)) {
469 if (total == INIT_TIMEOUT_MSECS) {
470 printk(KERN_DEBUG "applesmc: device has"
471 " already been initialized"
472 " (0x%02x, 0x%02x).\n",
473 buffer[0], buffer[1]);
474 } else {
475 printk(KERN_DEBUG "applesmc: device"
476 " successfully initialized"
477 " (0x%02x, 0x%02x).\n",
478 buffer[0], buffer[1]);
479 }
480 ret = 0;
481 goto out;
482 }
483 buffer[0] = 0xe0;
484 buffer[1] = 0x00;
485 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
486 msleep(INIT_WAIT_MSECS);
487 }
488
489 printk(KERN_WARNING "applesmc: failed to init the device\n");
490
491out:
492 mutex_unlock(&applesmc_lock);
493 return ret;
494}
495
496/*
497 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
498 * applesmc_lock.
499 */
500static int applesmc_get_fan_count(void)
501{
502 int ret;
503 u8 buffer[1];
504
505 mutex_lock(&applesmc_lock);
506
507 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
508
509 mutex_unlock(&applesmc_lock);
510 if (ret)
511 return ret;
512 else
513 return buffer[0];
514}
515
516/* Device model stuff */
517static int applesmc_probe(struct platform_device *dev)
518{
519 int ret;
520
521 ret = applesmc_device_init();
522 if (ret)
523 return ret;
524
525 printk(KERN_INFO "applesmc: device successfully initialized.\n");
526 return 0;
527}
528
Henrik Rydberga976f152009-09-21 17:04:50 -0700529/* Synchronize device with memorized backlight state */
530static int applesmc_pm_resume(struct device *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700531{
Henrik Rydberga976f152009-09-21 17:04:50 -0700532 mutex_lock(&applesmc_lock);
533 if (applesmc_light)
534 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
535 mutex_unlock(&applesmc_lock);
536 return 0;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700537}
538
Henrik Rydberga976f152009-09-21 17:04:50 -0700539/* Reinitialize device on resume from hibernation */
540static int applesmc_pm_restore(struct device *dev)
541{
542 int ret = applesmc_device_init();
543 if (ret)
544 return ret;
545 return applesmc_pm_resume(dev);
546}
547
Alexey Dobriyan47145212009-12-14 18:00:08 -0800548static const struct dev_pm_ops applesmc_pm_ops = {
Henrik Rydberga976f152009-09-21 17:04:50 -0700549 .resume = applesmc_pm_resume,
550 .restore = applesmc_pm_restore,
551};
552
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700553static struct platform_driver applesmc_driver = {
554 .probe = applesmc_probe,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700555 .driver = {
556 .name = "applesmc",
557 .owner = THIS_MODULE,
Henrik Rydberga976f152009-09-21 17:04:50 -0700558 .pm = &applesmc_pm_ops,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700559 },
560};
561
562/*
563 * applesmc_calibrate - Set our "resting" values. Callers must
564 * hold applesmc_lock.
565 */
566static void applesmc_calibrate(void)
567{
568 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
569 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
570 rest_x = -rest_x;
571}
572
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400573static void applesmc_idev_poll(struct input_polled_dev *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700574{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400575 struct input_dev *idev = dev->input;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700576 s16 x, y;
577
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400578 mutex_lock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700579
580 if (applesmc_read_motion_sensor(SENSOR_X, &x))
581 goto out;
582 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
583 goto out;
584
585 x = -x;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400586 input_report_abs(idev, ABS_X, x - rest_x);
587 input_report_abs(idev, ABS_Y, y - rest_y);
588 input_sync(idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700589
590out:
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700591 mutex_unlock(&applesmc_lock);
592}
593
594/* Sysfs Files */
595
Nicolas Boichatfa744192007-05-23 13:58:13 -0700596static ssize_t applesmc_name_show(struct device *dev,
597 struct device_attribute *attr, char *buf)
598{
599 return snprintf(buf, PAGE_SIZE, "applesmc\n");
600}
601
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700602static ssize_t applesmc_position_show(struct device *dev,
603 struct device_attribute *attr, char *buf)
604{
605 int ret;
606 s16 x, y, z;
607
608 mutex_lock(&applesmc_lock);
609
610 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
611 if (ret)
612 goto out;
613 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
614 if (ret)
615 goto out;
616 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
617 if (ret)
618 goto out;
619
620out:
621 mutex_unlock(&applesmc_lock);
622 if (ret)
623 return ret;
624 else
625 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
626}
627
628static ssize_t applesmc_light_show(struct device *dev,
629 struct device_attribute *attr, char *sysfsbuf)
630{
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700631 static int data_length;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700632 int ret;
633 u8 left = 0, right = 0;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700634 u8 buffer[10], query[6];
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700635
636 mutex_lock(&applesmc_lock);
637
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700638 if (!data_length) {
639 ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
640 if (ret)
641 goto out;
642 data_length = clamp_val(query[0], 0, 10);
643 printk(KERN_INFO "applesmc: light sensor data length set to "
644 "%d\n", data_length);
645 }
646
647 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Alex Murrayc3d63622009-01-15 13:51:08 -0800648 /* newer macbooks report a single 10-bit bigendian value */
649 if (data_length == 10) {
650 left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
651 goto out;
652 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700653 left = buffer[2];
654 if (ret)
655 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700656 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700657 right = buffer[2];
658
659out:
660 mutex_unlock(&applesmc_lock);
661 if (ret)
662 return ret;
663 else
664 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
665}
666
Alex Murrayfa5575c2010-05-27 19:58:54 +0200667/* Displays sensor key as label */
668static ssize_t applesmc_show_sensor_label(struct device *dev,
669 struct device_attribute *devattr, char *sysfsbuf)
670{
671 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
672 const char *key =
673 temperature_sensors_sets[applesmc_temperature_set][attr->index];
674
675 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
676}
677
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700678/* Displays degree Celsius * 1000 */
679static ssize_t applesmc_show_temperature(struct device *dev,
680 struct device_attribute *devattr, char *sysfsbuf)
681{
682 int ret;
683 u8 buffer[2];
684 unsigned int temp;
685 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
686 const char* key =
687 temperature_sensors_sets[applesmc_temperature_set][attr->index];
688
689 mutex_lock(&applesmc_lock);
690
691 ret = applesmc_read_key(key, buffer, 2);
692 temp = buffer[0]*1000;
693 temp += (buffer[1] >> 6) * 250;
694
695 mutex_unlock(&applesmc_lock);
696
697 if (ret)
698 return ret;
699 else
700 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
701}
702
703static ssize_t applesmc_show_fan_speed(struct device *dev,
704 struct device_attribute *attr, char *sysfsbuf)
705{
706 int ret;
707 unsigned int speed = 0;
708 char newkey[5];
709 u8 buffer[2];
710 struct sensor_device_attribute_2 *sensor_attr =
711 to_sensor_dev_attr_2(attr);
712
713 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
714 newkey[1] = '0' + sensor_attr->index;
715 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
716 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
717 newkey[4] = 0;
718
719 mutex_lock(&applesmc_lock);
720
721 ret = applesmc_read_key(newkey, buffer, 2);
722 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
723
724 mutex_unlock(&applesmc_lock);
725 if (ret)
726 return ret;
727 else
728 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
729}
730
731static ssize_t applesmc_store_fan_speed(struct device *dev,
732 struct device_attribute *attr,
733 const char *sysfsbuf, size_t count)
734{
735 int ret;
736 u32 speed;
737 char newkey[5];
738 u8 buffer[2];
739 struct sensor_device_attribute_2 *sensor_attr =
740 to_sensor_dev_attr_2(attr);
741
742 speed = simple_strtoul(sysfsbuf, NULL, 10);
743
744 if (speed > 0x4000) /* Bigger than a 14-bit value */
745 return -EINVAL;
746
747 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
748 newkey[1] = '0' + sensor_attr->index;
749 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
750 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
751 newkey[4] = 0;
752
753 mutex_lock(&applesmc_lock);
754
755 buffer[0] = (speed >> 6) & 0xff;
756 buffer[1] = (speed << 2) & 0xff;
757 ret = applesmc_write_key(newkey, buffer, 2);
758
759 mutex_unlock(&applesmc_lock);
760 if (ret)
761 return ret;
762 else
763 return count;
764}
765
766static ssize_t applesmc_show_fan_manual(struct device *dev,
767 struct device_attribute *devattr, char *sysfsbuf)
768{
769 int ret;
770 u16 manual = 0;
771 u8 buffer[2];
772 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
773
774 mutex_lock(&applesmc_lock);
775
776 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
777 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
778
779 mutex_unlock(&applesmc_lock);
780 if (ret)
781 return ret;
782 else
783 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
784}
785
786static ssize_t applesmc_store_fan_manual(struct device *dev,
787 struct device_attribute *devattr,
788 const char *sysfsbuf, size_t count)
789{
790 int ret;
791 u8 buffer[2];
792 u32 input;
793 u16 val;
794 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
795
796 input = simple_strtoul(sysfsbuf, NULL, 10);
797
798 mutex_lock(&applesmc_lock);
799
800 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
801 val = (buffer[0] << 8 | buffer[1]);
802 if (ret)
803 goto out;
804
805 if (input)
806 val = val | (0x01 << attr->index);
807 else
808 val = val & ~(0x01 << attr->index);
809
810 buffer[0] = (val >> 8) & 0xFF;
811 buffer[1] = val & 0xFF;
812
813 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
814
815out:
816 mutex_unlock(&applesmc_lock);
817 if (ret)
818 return ret;
819 else
820 return count;
821}
822
823static ssize_t applesmc_show_fan_position(struct device *dev,
824 struct device_attribute *attr, char *sysfsbuf)
825{
826 int ret;
827 char newkey[5];
828 u8 buffer[17];
829 struct sensor_device_attribute_2 *sensor_attr =
830 to_sensor_dev_attr_2(attr);
831
832 newkey[0] = FAN_POSITION[0];
833 newkey[1] = '0' + sensor_attr->index;
834 newkey[2] = FAN_POSITION[2];
835 newkey[3] = FAN_POSITION[3];
836 newkey[4] = 0;
837
838 mutex_lock(&applesmc_lock);
839
840 ret = applesmc_read_key(newkey, buffer, 16);
841 buffer[16] = 0;
842
843 mutex_unlock(&applesmc_lock);
844 if (ret)
845 return ret;
846 else
847 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
848}
849
850static ssize_t applesmc_calibrate_show(struct device *dev,
851 struct device_attribute *attr, char *sysfsbuf)
852{
853 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
854}
855
856static ssize_t applesmc_calibrate_store(struct device *dev,
857 struct device_attribute *attr, const char *sysfsbuf, size_t count)
858{
859 mutex_lock(&applesmc_lock);
860 applesmc_calibrate();
861 mutex_unlock(&applesmc_lock);
862
863 return count;
864}
865
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700866static void applesmc_backlight_set(struct work_struct *work)
867{
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700868 mutex_lock(&applesmc_lock);
Henrik Rydberga976f152009-09-21 17:04:50 -0700869 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700870 mutex_unlock(&applesmc_lock);
871}
872static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
873
874static void applesmc_brightness_set(struct led_classdev *led_cdev,
875 enum led_brightness value)
876{
877 int ret;
878
Henrik Rydberga976f152009-09-21 17:04:50 -0700879 backlight_state[0] = value;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700880 ret = queue_work(applesmc_led_wq, &backlight_work);
881
882 if (debug && (!ret))
883 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
884}
885
886static ssize_t applesmc_key_count_show(struct device *dev,
887 struct device_attribute *attr, char *sysfsbuf)
888{
889 int ret;
890 u8 buffer[4];
891 u32 count;
892
893 mutex_lock(&applesmc_lock);
894
895 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
896 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
897 ((u32)buffer[2]<<8) + buffer[3];
898
899 mutex_unlock(&applesmc_lock);
900 if (ret)
901 return ret;
902 else
903 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
904}
905
906static ssize_t applesmc_key_at_index_read_show(struct device *dev,
907 struct device_attribute *attr, char *sysfsbuf)
908{
909 char key[5];
910 char info[6];
911 int ret;
912
913 mutex_lock(&applesmc_lock);
914
915 ret = applesmc_get_key_at_index(key_at_index, key);
916
917 if (ret || !key[0]) {
918 mutex_unlock(&applesmc_lock);
919
920 return -EINVAL;
921 }
922
923 ret = applesmc_get_key_type(key, info);
924
925 if (ret) {
926 mutex_unlock(&applesmc_lock);
927
928 return ret;
929 }
930
931 /*
932 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
933 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
934 */
935 ret = applesmc_read_key(key, sysfsbuf, info[0]);
936
937 mutex_unlock(&applesmc_lock);
938
939 if (!ret) {
940 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400941 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700942 return ret;
943 }
944}
945
946static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
947 struct device_attribute *attr, char *sysfsbuf)
948{
949 char key[5];
950 char info[6];
951 int ret;
952
953 mutex_lock(&applesmc_lock);
954
955 ret = applesmc_get_key_at_index(key_at_index, key);
956
957 if (ret || !key[0]) {
958 mutex_unlock(&applesmc_lock);
959
960 return -EINVAL;
961 }
962
963 ret = applesmc_get_key_type(key, info);
964
965 mutex_unlock(&applesmc_lock);
966
967 if (!ret)
968 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
969 else
970 return ret;
971}
972
973static ssize_t applesmc_key_at_index_type_show(struct device *dev,
974 struct device_attribute *attr, char *sysfsbuf)
975{
976 char key[5];
977 char info[6];
978 int ret;
979
980 mutex_lock(&applesmc_lock);
981
982 ret = applesmc_get_key_at_index(key_at_index, key);
983
984 if (ret || !key[0]) {
985 mutex_unlock(&applesmc_lock);
986
987 return -EINVAL;
988 }
989
990 ret = applesmc_get_key_type(key, info);
991
992 mutex_unlock(&applesmc_lock);
993
994 if (!ret)
995 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
996 else
997 return ret;
998}
999
1000static ssize_t applesmc_key_at_index_name_show(struct device *dev,
1001 struct device_attribute *attr, char *sysfsbuf)
1002{
1003 char key[5];
1004 int ret;
1005
1006 mutex_lock(&applesmc_lock);
1007
1008 ret = applesmc_get_key_at_index(key_at_index, key);
1009
1010 mutex_unlock(&applesmc_lock);
1011
1012 if (!ret && key[0])
1013 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
1014 else
1015 return -EINVAL;
1016}
1017
1018static ssize_t applesmc_key_at_index_show(struct device *dev,
1019 struct device_attribute *attr, char *sysfsbuf)
1020{
1021 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
1022}
1023
1024static ssize_t applesmc_key_at_index_store(struct device *dev,
1025 struct device_attribute *attr, const char *sysfsbuf, size_t count)
1026{
1027 mutex_lock(&applesmc_lock);
1028
1029 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
1030
1031 mutex_unlock(&applesmc_lock);
1032
1033 return count;
1034}
1035
1036static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +01001037 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001038 .default_trigger = "nand-disk",
1039 .brightness_set = applesmc_brightness_set,
1040};
1041
Nicolas Boichatfa744192007-05-23 13:58:13 -07001042static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
1043
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001044static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
1045static DEVICE_ATTR(calibrate, 0644,
1046 applesmc_calibrate_show, applesmc_calibrate_store);
1047
1048static struct attribute *accelerometer_attributes[] = {
1049 &dev_attr_position.attr,
1050 &dev_attr_calibrate.attr,
1051 NULL
1052};
1053
1054static const struct attribute_group accelerometer_attributes_group =
1055 { .attrs = accelerometer_attributes };
1056
1057static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
1058
1059static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
1060static DEVICE_ATTR(key_at_index, 0644,
1061 applesmc_key_at_index_show, applesmc_key_at_index_store);
1062static DEVICE_ATTR(key_at_index_name, 0444,
1063 applesmc_key_at_index_name_show, NULL);
1064static DEVICE_ATTR(key_at_index_type, 0444,
1065 applesmc_key_at_index_type_show, NULL);
1066static DEVICE_ATTR(key_at_index_data_length, 0444,
1067 applesmc_key_at_index_data_length_show, NULL);
1068static DEVICE_ATTR(key_at_index_data, 0444,
1069 applesmc_key_at_index_read_show, NULL);
1070
1071static struct attribute *key_enumeration_attributes[] = {
1072 &dev_attr_key_count.attr,
1073 &dev_attr_key_at_index.attr,
1074 &dev_attr_key_at_index_name.attr,
1075 &dev_attr_key_at_index_type.attr,
1076 &dev_attr_key_at_index_data_length.attr,
1077 &dev_attr_key_at_index_data.attr,
1078 NULL
1079};
1080
1081static const struct attribute_group key_enumeration_group =
1082 { .attrs = key_enumeration_attributes };
1083
1084/*
1085 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1086 * - show actual speed
1087 * - show/store minimum speed
1088 * - show maximum speed
1089 * - show safe speed
1090 * - show/store target speed
1091 * - show/store manual mode
1092 */
1093#define sysfs_fan_speeds_offset(offset) \
1094static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1095 applesmc_show_fan_speed, NULL, 0, offset-1); \
1096\
1097static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1098 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1099\
1100static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1101 applesmc_show_fan_speed, NULL, 2, offset-1); \
1102\
1103static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1104 applesmc_show_fan_speed, NULL, 3, offset-1); \
1105\
1106static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1107 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1108\
1109static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1110 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1111\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001112static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001113 applesmc_show_fan_position, NULL, offset-1); \
1114\
1115static struct attribute *fan##offset##_attributes[] = { \
1116 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1117 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1118 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1119 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1120 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1121 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001122 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001123 NULL \
1124};
1125
1126/*
1127 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001128 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001129 */
1130sysfs_fan_speeds_offset(1);
1131sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001132sysfs_fan_speeds_offset(3);
1133sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001134
1135static const struct attribute_group fan_attribute_groups[] = {
1136 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001137 { .attrs = fan2_attributes },
1138 { .attrs = fan3_attributes },
1139 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001140};
1141
1142/*
1143 * Temperature sensors sysfs entries.
1144 */
Alex Murrayfa5575c2010-05-27 19:58:54 +02001145static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
1146 applesmc_show_sensor_label, NULL, 0);
1147static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
1148 applesmc_show_sensor_label, NULL, 1);
1149static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
1150 applesmc_show_sensor_label, NULL, 2);
1151static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
1152 applesmc_show_sensor_label, NULL, 3);
1153static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
1154 applesmc_show_sensor_label, NULL, 4);
1155static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
1156 applesmc_show_sensor_label, NULL, 5);
1157static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
1158 applesmc_show_sensor_label, NULL, 6);
1159static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
1160 applesmc_show_sensor_label, NULL, 7);
1161static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
1162 applesmc_show_sensor_label, NULL, 8);
1163static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
1164 applesmc_show_sensor_label, NULL, 9);
1165static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
1166 applesmc_show_sensor_label, NULL, 10);
1167static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
1168 applesmc_show_sensor_label, NULL, 11);
1169static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
1170 applesmc_show_sensor_label, NULL, 12);
1171static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
1172 applesmc_show_sensor_label, NULL, 13);
1173static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
1174 applesmc_show_sensor_label, NULL, 14);
1175static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
1176 applesmc_show_sensor_label, NULL, 15);
1177static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
1178 applesmc_show_sensor_label, NULL, 16);
1179static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
1180 applesmc_show_sensor_label, NULL, 17);
1181static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
1182 applesmc_show_sensor_label, NULL, 18);
1183static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
1184 applesmc_show_sensor_label, NULL, 19);
1185static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
1186 applesmc_show_sensor_label, NULL, 20);
1187static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
1188 applesmc_show_sensor_label, NULL, 21);
1189static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
1190 applesmc_show_sensor_label, NULL, 22);
1191static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
1192 applesmc_show_sensor_label, NULL, 23);
1193static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
1194 applesmc_show_sensor_label, NULL, 24);
1195static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
1196 applesmc_show_sensor_label, NULL, 25);
1197static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
1198 applesmc_show_sensor_label, NULL, 26);
1199static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
1200 applesmc_show_sensor_label, NULL, 27);
1201static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
1202 applesmc_show_sensor_label, NULL, 28);
1203static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
1204 applesmc_show_sensor_label, NULL, 29);
1205static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
1206 applesmc_show_sensor_label, NULL, 30);
1207static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
1208 applesmc_show_sensor_label, NULL, 31);
1209static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
1210 applesmc_show_sensor_label, NULL, 32);
1211static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
1212 applesmc_show_sensor_label, NULL, 33);
1213static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
1214 applesmc_show_sensor_label, NULL, 34);
1215static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
1216 applesmc_show_sensor_label, NULL, 35);
1217static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
1218 applesmc_show_sensor_label, NULL, 36);
1219static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
1220 applesmc_show_sensor_label, NULL, 37);
1221static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
1222 applesmc_show_sensor_label, NULL, 38);
1223static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
1224 applesmc_show_sensor_label, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001225static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1226 applesmc_show_temperature, NULL, 0);
1227static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1228 applesmc_show_temperature, NULL, 1);
1229static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1230 applesmc_show_temperature, NULL, 2);
1231static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1232 applesmc_show_temperature, NULL, 3);
1233static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1234 applesmc_show_temperature, NULL, 4);
1235static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1236 applesmc_show_temperature, NULL, 5);
1237static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1238 applesmc_show_temperature, NULL, 6);
1239static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1240 applesmc_show_temperature, NULL, 7);
1241static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1242 applesmc_show_temperature, NULL, 8);
1243static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1244 applesmc_show_temperature, NULL, 9);
1245static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1246 applesmc_show_temperature, NULL, 10);
1247static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1248 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001249static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1250 applesmc_show_temperature, NULL, 12);
1251static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1252 applesmc_show_temperature, NULL, 13);
1253static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1254 applesmc_show_temperature, NULL, 14);
1255static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1256 applesmc_show_temperature, NULL, 15);
1257static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1258 applesmc_show_temperature, NULL, 16);
1259static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1260 applesmc_show_temperature, NULL, 17);
1261static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1262 applesmc_show_temperature, NULL, 18);
1263static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1264 applesmc_show_temperature, NULL, 19);
1265static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1266 applesmc_show_temperature, NULL, 20);
1267static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1268 applesmc_show_temperature, NULL, 21);
1269static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1270 applesmc_show_temperature, NULL, 22);
1271static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1272 applesmc_show_temperature, NULL, 23);
1273static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1274 applesmc_show_temperature, NULL, 24);
1275static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1276 applesmc_show_temperature, NULL, 25);
1277static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1278 applesmc_show_temperature, NULL, 26);
1279static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1280 applesmc_show_temperature, NULL, 27);
1281static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1282 applesmc_show_temperature, NULL, 28);
1283static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1284 applesmc_show_temperature, NULL, 29);
1285static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1286 applesmc_show_temperature, NULL, 30);
1287static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1288 applesmc_show_temperature, NULL, 31);
1289static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1290 applesmc_show_temperature, NULL, 32);
1291static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1292 applesmc_show_temperature, NULL, 33);
1293static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1294 applesmc_show_temperature, NULL, 34);
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001295static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
1296 applesmc_show_temperature, NULL, 35);
1297static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
1298 applesmc_show_temperature, NULL, 36);
1299static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
1300 applesmc_show_temperature, NULL, 37);
1301static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
1302 applesmc_show_temperature, NULL, 38);
1303static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
1304 applesmc_show_temperature, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001305
Alex Murrayfa5575c2010-05-27 19:58:54 +02001306static struct attribute *label_attributes[] = {
1307 &sensor_dev_attr_temp1_label.dev_attr.attr,
1308 &sensor_dev_attr_temp2_label.dev_attr.attr,
1309 &sensor_dev_attr_temp3_label.dev_attr.attr,
1310 &sensor_dev_attr_temp4_label.dev_attr.attr,
1311 &sensor_dev_attr_temp5_label.dev_attr.attr,
1312 &sensor_dev_attr_temp6_label.dev_attr.attr,
1313 &sensor_dev_attr_temp7_label.dev_attr.attr,
1314 &sensor_dev_attr_temp8_label.dev_attr.attr,
1315 &sensor_dev_attr_temp9_label.dev_attr.attr,
1316 &sensor_dev_attr_temp10_label.dev_attr.attr,
1317 &sensor_dev_attr_temp11_label.dev_attr.attr,
1318 &sensor_dev_attr_temp12_label.dev_attr.attr,
1319 &sensor_dev_attr_temp13_label.dev_attr.attr,
1320 &sensor_dev_attr_temp14_label.dev_attr.attr,
1321 &sensor_dev_attr_temp15_label.dev_attr.attr,
1322 &sensor_dev_attr_temp16_label.dev_attr.attr,
1323 &sensor_dev_attr_temp17_label.dev_attr.attr,
1324 &sensor_dev_attr_temp18_label.dev_attr.attr,
1325 &sensor_dev_attr_temp19_label.dev_attr.attr,
1326 &sensor_dev_attr_temp20_label.dev_attr.attr,
1327 &sensor_dev_attr_temp21_label.dev_attr.attr,
1328 &sensor_dev_attr_temp22_label.dev_attr.attr,
1329 &sensor_dev_attr_temp23_label.dev_attr.attr,
1330 &sensor_dev_attr_temp24_label.dev_attr.attr,
1331 &sensor_dev_attr_temp25_label.dev_attr.attr,
1332 &sensor_dev_attr_temp26_label.dev_attr.attr,
1333 &sensor_dev_attr_temp27_label.dev_attr.attr,
1334 &sensor_dev_attr_temp28_label.dev_attr.attr,
1335 &sensor_dev_attr_temp29_label.dev_attr.attr,
1336 &sensor_dev_attr_temp30_label.dev_attr.attr,
1337 &sensor_dev_attr_temp31_label.dev_attr.attr,
1338 &sensor_dev_attr_temp32_label.dev_attr.attr,
1339 &sensor_dev_attr_temp33_label.dev_attr.attr,
1340 &sensor_dev_attr_temp34_label.dev_attr.attr,
1341 &sensor_dev_attr_temp35_label.dev_attr.attr,
1342 &sensor_dev_attr_temp36_label.dev_attr.attr,
1343 &sensor_dev_attr_temp37_label.dev_attr.attr,
1344 &sensor_dev_attr_temp38_label.dev_attr.attr,
1345 &sensor_dev_attr_temp39_label.dev_attr.attr,
1346 &sensor_dev_attr_temp40_label.dev_attr.attr,
1347 NULL
1348};
1349
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001350static struct attribute *temperature_attributes[] = {
1351 &sensor_dev_attr_temp1_input.dev_attr.attr,
1352 &sensor_dev_attr_temp2_input.dev_attr.attr,
1353 &sensor_dev_attr_temp3_input.dev_attr.attr,
1354 &sensor_dev_attr_temp4_input.dev_attr.attr,
1355 &sensor_dev_attr_temp5_input.dev_attr.attr,
1356 &sensor_dev_attr_temp6_input.dev_attr.attr,
1357 &sensor_dev_attr_temp7_input.dev_attr.attr,
1358 &sensor_dev_attr_temp8_input.dev_attr.attr,
1359 &sensor_dev_attr_temp9_input.dev_attr.attr,
1360 &sensor_dev_attr_temp10_input.dev_attr.attr,
1361 &sensor_dev_attr_temp11_input.dev_attr.attr,
1362 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001363 &sensor_dev_attr_temp13_input.dev_attr.attr,
1364 &sensor_dev_attr_temp14_input.dev_attr.attr,
1365 &sensor_dev_attr_temp15_input.dev_attr.attr,
1366 &sensor_dev_attr_temp16_input.dev_attr.attr,
1367 &sensor_dev_attr_temp17_input.dev_attr.attr,
1368 &sensor_dev_attr_temp18_input.dev_attr.attr,
1369 &sensor_dev_attr_temp19_input.dev_attr.attr,
1370 &sensor_dev_attr_temp20_input.dev_attr.attr,
1371 &sensor_dev_attr_temp21_input.dev_attr.attr,
1372 &sensor_dev_attr_temp22_input.dev_attr.attr,
1373 &sensor_dev_attr_temp23_input.dev_attr.attr,
1374 &sensor_dev_attr_temp24_input.dev_attr.attr,
1375 &sensor_dev_attr_temp25_input.dev_attr.attr,
1376 &sensor_dev_attr_temp26_input.dev_attr.attr,
1377 &sensor_dev_attr_temp27_input.dev_attr.attr,
1378 &sensor_dev_attr_temp28_input.dev_attr.attr,
1379 &sensor_dev_attr_temp29_input.dev_attr.attr,
1380 &sensor_dev_attr_temp30_input.dev_attr.attr,
1381 &sensor_dev_attr_temp31_input.dev_attr.attr,
1382 &sensor_dev_attr_temp32_input.dev_attr.attr,
1383 &sensor_dev_attr_temp33_input.dev_attr.attr,
1384 &sensor_dev_attr_temp34_input.dev_attr.attr,
1385 &sensor_dev_attr_temp35_input.dev_attr.attr,
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001386 &sensor_dev_attr_temp36_input.dev_attr.attr,
1387 &sensor_dev_attr_temp37_input.dev_attr.attr,
1388 &sensor_dev_attr_temp38_input.dev_attr.attr,
1389 &sensor_dev_attr_temp39_input.dev_attr.attr,
1390 &sensor_dev_attr_temp40_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001391 NULL
1392};
1393
1394static const struct attribute_group temperature_attributes_group =
1395 { .attrs = temperature_attributes };
1396
Alex Murrayfa5575c2010-05-27 19:58:54 +02001397static const struct attribute_group label_attributes_group = {
1398 .attrs = label_attributes
1399};
1400
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001401/* Module stuff */
1402
1403/*
1404 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1405 */
Jeff Garzik18552562007-10-03 15:15:40 -04001406static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001407{
1408 int i = 0;
1409 struct dmi_match_data* dmi_data = id->driver_data;
1410 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1411 applesmc_accelerometer = dmi_data->accelerometer;
1412 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1413 applesmc_accelerometer ? "with" : "without");
1414 applesmc_light = dmi_data->light;
1415 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1416 applesmc_light ? "with" : "without");
1417
1418 applesmc_temperature_set = dmi_data->temperature_set;
1419 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1420 i++;
1421 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1422 return 1;
1423}
1424
1425/* Create accelerometer ressources */
1426static int applesmc_create_accelerometer(void)
1427{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001428 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001429 int ret;
1430
1431 ret = sysfs_create_group(&pdev->dev.kobj,
1432 &accelerometer_attributes_group);
1433 if (ret)
1434 goto out;
1435
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001436 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001437 if (!applesmc_idev) {
1438 ret = -ENOMEM;
1439 goto out_sysfs;
1440 }
1441
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001442 applesmc_idev->poll = applesmc_idev_poll;
1443 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1444
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001445 /* initial calibrate for the input device */
1446 applesmc_calibrate();
1447
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001448 /* initialize the input device */
1449 idev = applesmc_idev->input;
1450 idev->name = "applesmc";
1451 idev->id.bustype = BUS_HOST;
1452 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001453 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001454 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001455 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001456 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001457 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1458
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001459 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001460 if (ret)
1461 goto out_idev;
1462
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001463 return 0;
1464
1465out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001466 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001467
1468out_sysfs:
1469 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1470
1471out:
1472 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1473 return ret;
1474}
1475
1476/* Release all ressources used by the accelerometer */
1477static void applesmc_release_accelerometer(void)
1478{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001479 input_unregister_polled_device(applesmc_idev);
1480 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001481 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1482}
1483
1484static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1485/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1486 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001487/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001488 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001489/* MacBook: accelerometer and temperature set 2 */
1490 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1491/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001492 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001493/* MacPro: temperature set 4 */
1494 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001495/* iMac: temperature set 5 */
1496 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Henrik Rydberg468cc032008-11-12 13:24:58 -08001497/* MacBook3, MacBook4: accelerometer and temperature set 6 */
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001498 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001499/* MacBook Air: accelerometer, backlight and temperature set 7 */
1500 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001501/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1502 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001503/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1504 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001505/* iMac 5: light sensor only, temperature set 10 */
1506 { .accelerometer = 0, .light = 0, .temperature_set = 10 },
Henrik Rydberg181209a12008-11-06 12:53:20 -08001507/* MacBook 5: accelerometer, backlight and temperature set 11 */
1508 { .accelerometer = 1, .light = 1, .temperature_set = 11 },
Henrik Rydberga6660322008-11-06 12:53:21 -08001509/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
1510 { .accelerometer = 1, .light = 1, .temperature_set = 12 },
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001511/* iMac 8: light sensor only, temperature set 13 */
1512 { .accelerometer = 0, .light = 0, .temperature_set = 13 },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001513/* iMac 6: light sensor only, temperature set 14 */
1514 { .accelerometer = 0, .light = 0, .temperature_set = 14 },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001515/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
1516 { .accelerometer = 1, .light = 1, .temperature_set = 15 },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001517/* MacPro3,1: temperature set 16 */
1518 { .accelerometer = 0, .light = 0, .temperature_set = 16 },
Justin P. Mattocke1741712010-04-14 16:14:10 +02001519/* iMac 9,1: light sensor only, temperature set 17 */
1520 { .accelerometer = 0, .light = 0, .temperature_set = 17 },
1521/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
1522 { .accelerometer = 1, .light = 1, .temperature_set = 18 },
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +02001523/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
1524 { .accelerometer = 1, .light = 1, .temperature_set = 19 },
1525/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
1526 { .accelerometer = 1, .light = 1, .temperature_set = 20 },
Bernhard Froemel872bad52010-05-27 19:58:52 +02001527/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
1528 { .accelerometer = 1, .light = 1, .temperature_set = 21 },
Henrik Rydberg405eaa12010-05-27 19:58:53 +02001529/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
1530 { .accelerometer = 1, .light = 1, .temperature_set = 22 },
Edgar Hucek132af032010-11-09 15:15:01 +00001531/* MacBook Air 3,1: accelerometer, backlight and temperature set 23 */
1532 { .accelerometer = 0, .light = 0, .temperature_set = 23 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001533};
1534
1535/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1536 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1537static __initdata struct dmi_system_id applesmc_whitelist[] = {
Edgar Hucek132af032010-11-09 15:15:01 +00001538 { applesmc_dmi_match, "Apple MacBook Air 3", {
1539 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1540 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3") },
1541 &applesmc_dmi_data[23]},
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001542 { applesmc_dmi_match, "Apple MacBook Air 2", {
1543 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1544 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
1545 &applesmc_dmi_data[15]},
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001546 { applesmc_dmi_match, "Apple MacBook Air", {
1547 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1548 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001549 &applesmc_dmi_data[7]},
Henrik Rydberg405eaa12010-05-27 19:58:53 +02001550 { applesmc_dmi_match, "Apple MacBook Pro 7", {
1551 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1552 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
1553 &applesmc_dmi_data[22]},
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +02001554 { applesmc_dmi_match, "Apple MacBook Pro 5,4", {
1555 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1556 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
1557 &applesmc_dmi_data[20]},
1558 { applesmc_dmi_match, "Apple MacBook Pro 5,3", {
1559 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1560 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
1561 &applesmc_dmi_data[19]},
Bernhard Froemel872bad52010-05-27 19:58:52 +02001562 { applesmc_dmi_match, "Apple MacBook Pro 6", {
1563 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1564 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
1565 &applesmc_dmi_data[21]},
Henrik Rydberga6660322008-11-06 12:53:21 -08001566 { applesmc_dmi_match, "Apple MacBook Pro 5", {
1567 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1568 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
1569 &applesmc_dmi_data[12]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001570 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1571 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1572 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1573 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001574 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1575 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1576 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1577 &applesmc_dmi_data[9]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001578 { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
1579 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
1580 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
1581 &applesmc_dmi_data[18]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001582 { applesmc_dmi_match, "Apple MacBook Pro", {
1583 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1584 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001585 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001586 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001587 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001588 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001589 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001590 { applesmc_dmi_match, "Apple MacBook (v3)", {
1591 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1592 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001593 &applesmc_dmi_data[6]},
Henrik Rydberg468cc032008-11-12 13:24:58 -08001594 { applesmc_dmi_match, "Apple MacBook 4", {
1595 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1596 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
1597 &applesmc_dmi_data[6]},
Henrik Rydberg181209a12008-11-06 12:53:20 -08001598 { applesmc_dmi_match, "Apple MacBook 5", {
1599 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1600 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
1601 &applesmc_dmi_data[11]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001602 { applesmc_dmi_match, "Apple MacBook", {
1603 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1604 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001605 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001606 { applesmc_dmi_match, "Apple Macmini", {
1607 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1608 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001609 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001610 { applesmc_dmi_match, "Apple MacPro2", {
1611 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1612 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001613 &applesmc_dmi_data[4]},
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001614 { applesmc_dmi_match, "Apple MacPro3", {
1615 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1616 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
1617 &applesmc_dmi_data[16]},
Henrik Rydberg45a3a362008-11-19 15:36:42 -08001618 { applesmc_dmi_match, "Apple MacPro", {
1619 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1620 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1621 &applesmc_dmi_data[4]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001622 { applesmc_dmi_match, "Apple iMac 9,1", {
1623 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
1624 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
1625 &applesmc_dmi_data[17]},
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001626 { applesmc_dmi_match, "Apple iMac 8", {
1627 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1628 DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
1629 &applesmc_dmi_data[13]},
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001630 { applesmc_dmi_match, "Apple iMac 6", {
1631 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1632 DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
1633 &applesmc_dmi_data[14]},
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001634 { applesmc_dmi_match, "Apple iMac 5", {
1635 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1636 DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
1637 &applesmc_dmi_data[10]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001638 { applesmc_dmi_match, "Apple iMac", {
1639 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1640 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001641 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001642 { .ident = NULL }
1643};
1644
1645static int __init applesmc_init(void)
1646{
1647 int ret;
1648 int count;
1649 int i;
1650
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001651 if (!dmi_check_system(applesmc_whitelist)) {
1652 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1653 ret = -ENODEV;
1654 goto out;
1655 }
1656
1657 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1658 "applesmc")) {
1659 ret = -ENXIO;
1660 goto out;
1661 }
1662
1663 ret = platform_driver_register(&applesmc_driver);
1664 if (ret)
1665 goto out_region;
1666
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001667 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1668 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001669 if (IS_ERR(pdev)) {
1670 ret = PTR_ERR(pdev);
1671 goto out_driver;
1672 }
1673
Nicolas Boichatfa744192007-05-23 13:58:13 -07001674 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001675 if (ret)
1676 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001677
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001678 /* Create key enumeration sysfs files */
1679 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1680 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001681 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001682
1683 /* create fan files */
1684 count = applesmc_get_fan_count();
Henrik Rydberg0559a532010-05-11 09:17:47 +02001685 if (count < 0)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001686 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
Henrik Rydberg0559a532010-05-11 09:17:47 +02001687 else
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001688 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1689
Henrik Rydberg0559a532010-05-11 09:17:47 +02001690 if (count > 4) {
1691 count = 4;
1692 printk(KERN_WARNING "applesmc: More than 4 fans found,"
1693 " but at most 4 fans are supported"
1694 " by the driver.\n");
1695 }
1696
1697 while (fans_handled < count) {
1698 ret = sysfs_create_group(&pdev->dev.kobj,
1699 &fan_attribute_groups[fans_handled]);
1700 if (ret)
1701 goto out_fans;
1702 fans_handled++;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001703 }
1704
1705 for (i = 0;
1706 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1707 i++) {
Alex Murrayfa5575c2010-05-27 19:58:54 +02001708 if (temperature_attributes[i] == NULL ||
1709 label_attributes[i] == NULL) {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001710 printk(KERN_ERR "applesmc: More temperature sensors "
1711 "in temperature_sensors_sets (at least %i)"
1712 "than available sysfs files in "
1713 "temperature_attributes (%i), please report "
1714 "this bug.\n", i, i-1);
1715 goto out_temperature;
1716 }
1717 ret = sysfs_create_file(&pdev->dev.kobj,
1718 temperature_attributes[i]);
1719 if (ret)
1720 goto out_temperature;
Alex Murrayfa5575c2010-05-27 19:58:54 +02001721 ret = sysfs_create_file(&pdev->dev.kobj,
1722 label_attributes[i]);
1723 if (ret)
1724 goto out_temperature;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001725 }
1726
1727 if (applesmc_accelerometer) {
1728 ret = applesmc_create_accelerometer();
1729 if (ret)
1730 goto out_temperature;
1731 }
1732
1733 if (applesmc_light) {
1734 /* Add light sensor file */
1735 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1736 if (ret)
1737 goto out_accelerometer;
1738
1739 /* Create the workqueue */
1740 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1741 if (!applesmc_led_wq) {
1742 ret = -ENOMEM;
1743 goto out_light_sysfs;
1744 }
1745
1746 /* register as a led device */
1747 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1748 if (ret < 0)
1749 goto out_light_wq;
1750 }
1751
Tony Jones1beeffe2007-08-20 13:46:20 -07001752 hwmon_dev = hwmon_device_register(&pdev->dev);
1753 if (IS_ERR(hwmon_dev)) {
1754 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001755 goto out_light_ledclass;
1756 }
1757
1758 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1759
1760 return 0;
1761
1762out_light_ledclass:
1763 if (applesmc_light)
1764 led_classdev_unregister(&applesmc_backlight);
1765out_light_wq:
1766 if (applesmc_light)
1767 destroy_workqueue(applesmc_led_wq);
1768out_light_sysfs:
1769 if (applesmc_light)
1770 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1771out_accelerometer:
1772 if (applesmc_accelerometer)
1773 applesmc_release_accelerometer();
1774out_temperature:
Alex Murrayfa5575c2010-05-27 19:58:54 +02001775 sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001776 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
Henrik Rydberg0559a532010-05-11 09:17:47 +02001777out_fans:
1778 while (fans_handled)
1779 sysfs_remove_group(&pdev->dev.kobj,
1780 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001781 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001782out_name:
1783 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001784out_device:
1785 platform_device_unregister(pdev);
1786out_driver:
1787 platform_driver_unregister(&applesmc_driver);
1788out_region:
1789 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1790out:
1791 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1792 return ret;
1793}
1794
1795static void __exit applesmc_exit(void)
1796{
Tony Jones1beeffe2007-08-20 13:46:20 -07001797 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001798 if (applesmc_light) {
1799 led_classdev_unregister(&applesmc_backlight);
1800 destroy_workqueue(applesmc_led_wq);
1801 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1802 }
1803 if (applesmc_accelerometer)
1804 applesmc_release_accelerometer();
Alex Murrayfa5575c2010-05-27 19:58:54 +02001805 sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001806 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
Henrik Rydberg0559a532010-05-11 09:17:47 +02001807 while (fans_handled)
1808 sysfs_remove_group(&pdev->dev.kobj,
1809 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001810 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001811 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001812 platform_device_unregister(pdev);
1813 platform_driver_unregister(&applesmc_driver);
1814 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1815
1816 printk(KERN_INFO "applesmc: driver unloaded.\n");
1817}
1818
1819module_init(applesmc_init);
1820module_exit(applesmc_exit);
1821
1822MODULE_AUTHOR("Nicolas Boichat");
1823MODULE_DESCRIPTION("Apple SMC");
1824MODULE_LICENSE("GPL v2");
Henrik Rydbergdc924ef2008-12-01 13:13:49 -08001825MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);