blob: 87a5fd51dd5e889d4607f6146e9a26e984e2e79b [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 Rameshfb9f88e12009-01-29 14:25:24 -080086static const char *temperature_sensors_sets[][41] = {
Martin Szulecki1bed24b2007-07-09 11:41:36 -070087/* Set 0: Macbook Pro */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070088 { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
89 "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080090/* Set 1: Macbook2 set */
91 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
92 "Th0S", "Th1H", NULL },
93/* Set 2: Macbook set */
Martin Szulecki1bed24b2007-07-09 11:41:36 -070094 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
95 "Th1H", "Ts0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080096/* Set 3: Macmini set */
René Rebe8de57702007-10-16 14:19:20 -070097 { "TC0D", "TC0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080098/* Set 4: Mac Pro (2 x Quad-Core) */
René Rebe8de57702007-10-16 14:19:20 -070099 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
100 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
101 "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
102 "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
103 "TM9S", "TN0H", "TS0C", NULL },
Roberto De Ioris9f86f282008-08-15 00:40:30 -0700104/* Set 5: iMac */
105 { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
106 "Tp0C", NULL },
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -0700107/* Set 6: Macbook3 set */
108 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
109 "Th0S", "Th1H", NULL },
Henrik Rydbergf5274c92008-10-18 20:27:40 -0700110/* Set 7: Macbook Air */
111 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
112 "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
Henrik Rydbergd7549902008-10-18 20:27:41 -0700113/* Set 8: Macbook Pro 4,1 (Penryn) */
114 { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
115 "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -0700116/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
117 { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
118 "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -0800119/* Set 10: iMac 5,1 */
120 { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL },
Henrik Rydberg181209a2008-11-06 12:53:20 -0800121/* Set 11: Macbook 5,1 */
122 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P",
123 "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL },
Henrik Rydberga6660322008-11-06 12:53:21 -0800124/* Set 12: Macbook Pro 5,1 */
125 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
126 "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0",
127 "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL },
Henrik Rydbergeefc4882008-11-06 12:53:22 -0800128/* Set 13: iMac 8,1 */
129 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
130 "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -0800131/* Set 14: iMac 6,1 */
132 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
133 "TO0P", "Tp0P", NULL },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -0800134/* Set 15: MacBook Air 2,1 */
135 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0",
136 "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P",
137 "Ts0S", NULL },
Bharath Rameshfb9f88e12009-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/*
Henrik Rydberg2344cd02010-11-09 15:15:02 +0000451 * applesmc_device_init - initialize the accelerometer. Can sleep.
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700452 */
Henrik Rydberg2344cd02010-11-09 15:15:02 +0000453static void applesmc_device_init(void)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700454{
Henrik Rydberg2344cd02010-11-09 15:15:02 +0000455 int total;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700456 u8 buffer[2];
457
458 if (!applesmc_accelerometer)
Henrik Rydberg2344cd02010-11-09 15:15:02 +0000459 return;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700460
461 mutex_lock(&applesmc_lock);
462
463 for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700464 if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
Henrik Rydberg2344cd02010-11-09 15:15:02 +0000465 (buffer[0] != 0x00 || buffer[1] != 0x00))
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700466 goto out;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700467 buffer[0] = 0xe0;
468 buffer[1] = 0x00;
469 applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
470 msleep(INIT_WAIT_MSECS);
471 }
472
473 printk(KERN_WARNING "applesmc: failed to init the device\n");
474
475out:
476 mutex_unlock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700477}
478
479/*
480 * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
481 * applesmc_lock.
482 */
483static int applesmc_get_fan_count(void)
484{
485 int ret;
486 u8 buffer[1];
487
488 mutex_lock(&applesmc_lock);
489
490 ret = applesmc_read_key(FANS_COUNT, buffer, 1);
491
492 mutex_unlock(&applesmc_lock);
493 if (ret)
494 return ret;
495 else
496 return buffer[0];
497}
498
499/* Device model stuff */
500static int applesmc_probe(struct platform_device *dev)
501{
Henrik Rydberg2344cd02010-11-09 15:15:02 +0000502 applesmc_device_init();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700503
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700504 return 0;
505}
506
Henrik Rydberga976f152009-09-21 17:04:50 -0700507/* Synchronize device with memorized backlight state */
508static int applesmc_pm_resume(struct device *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700509{
Henrik Rydberga976f152009-09-21 17:04:50 -0700510 mutex_lock(&applesmc_lock);
511 if (applesmc_light)
512 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
513 mutex_unlock(&applesmc_lock);
514 return 0;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700515}
516
Henrik Rydberga976f152009-09-21 17:04:50 -0700517/* Reinitialize device on resume from hibernation */
518static int applesmc_pm_restore(struct device *dev)
519{
Henrik Rydberg2344cd02010-11-09 15:15:02 +0000520 applesmc_device_init();
Henrik Rydberga976f152009-09-21 17:04:50 -0700521 return applesmc_pm_resume(dev);
522}
523
Alexey Dobriyan47145212009-12-14 18:00:08 -0800524static const struct dev_pm_ops applesmc_pm_ops = {
Henrik Rydberga976f152009-09-21 17:04:50 -0700525 .resume = applesmc_pm_resume,
526 .restore = applesmc_pm_restore,
527};
528
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700529static struct platform_driver applesmc_driver = {
530 .probe = applesmc_probe,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700531 .driver = {
532 .name = "applesmc",
533 .owner = THIS_MODULE,
Henrik Rydberga976f152009-09-21 17:04:50 -0700534 .pm = &applesmc_pm_ops,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700535 },
536};
537
538/*
539 * applesmc_calibrate - Set our "resting" values. Callers must
540 * hold applesmc_lock.
541 */
542static void applesmc_calibrate(void)
543{
544 applesmc_read_motion_sensor(SENSOR_X, &rest_x);
545 applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
546 rest_x = -rest_x;
547}
548
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400549static void applesmc_idev_poll(struct input_polled_dev *dev)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700550{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400551 struct input_dev *idev = dev->input;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700552 s16 x, y;
553
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400554 mutex_lock(&applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700555
556 if (applesmc_read_motion_sensor(SENSOR_X, &x))
557 goto out;
558 if (applesmc_read_motion_sensor(SENSOR_Y, &y))
559 goto out;
560
561 x = -x;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400562 input_report_abs(idev, ABS_X, x - rest_x);
563 input_report_abs(idev, ABS_Y, y - rest_y);
564 input_sync(idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700565
566out:
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700567 mutex_unlock(&applesmc_lock);
568}
569
570/* Sysfs Files */
571
Nicolas Boichatfa744192007-05-23 13:58:13 -0700572static ssize_t applesmc_name_show(struct device *dev,
573 struct device_attribute *attr, char *buf)
574{
575 return snprintf(buf, PAGE_SIZE, "applesmc\n");
576}
577
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700578static ssize_t applesmc_position_show(struct device *dev,
579 struct device_attribute *attr, char *buf)
580{
581 int ret;
582 s16 x, y, z;
583
584 mutex_lock(&applesmc_lock);
585
586 ret = applesmc_read_motion_sensor(SENSOR_X, &x);
587 if (ret)
588 goto out;
589 ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
590 if (ret)
591 goto out;
592 ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
593 if (ret)
594 goto out;
595
596out:
597 mutex_unlock(&applesmc_lock);
598 if (ret)
599 return ret;
600 else
601 return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
602}
603
604static ssize_t applesmc_light_show(struct device *dev,
605 struct device_attribute *attr, char *sysfsbuf)
606{
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700607 static int data_length;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700608 int ret;
609 u8 left = 0, right = 0;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700610 u8 buffer[10], query[6];
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700611
612 mutex_lock(&applesmc_lock);
613
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700614 if (!data_length) {
615 ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
616 if (ret)
617 goto out;
618 data_length = clamp_val(query[0], 0, 10);
619 printk(KERN_INFO "applesmc: light sensor data length set to "
620 "%d\n", data_length);
621 }
622
623 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Alex Murrayc3d63622009-01-15 13:51:08 -0800624 /* newer macbooks report a single 10-bit bigendian value */
625 if (data_length == 10) {
626 left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
627 goto out;
628 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700629 left = buffer[2];
630 if (ret)
631 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700632 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700633 right = buffer[2];
634
635out:
636 mutex_unlock(&applesmc_lock);
637 if (ret)
638 return ret;
639 else
640 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
641}
642
Alex Murrayfa5575c2010-05-27 19:58:54 +0200643/* Displays sensor key as label */
644static ssize_t applesmc_show_sensor_label(struct device *dev,
645 struct device_attribute *devattr, char *sysfsbuf)
646{
647 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
648 const char *key =
649 temperature_sensors_sets[applesmc_temperature_set][attr->index];
650
651 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
652}
653
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700654/* Displays degree Celsius * 1000 */
655static ssize_t applesmc_show_temperature(struct device *dev,
656 struct device_attribute *devattr, char *sysfsbuf)
657{
658 int ret;
659 u8 buffer[2];
660 unsigned int temp;
661 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
662 const char* key =
663 temperature_sensors_sets[applesmc_temperature_set][attr->index];
664
665 mutex_lock(&applesmc_lock);
666
667 ret = applesmc_read_key(key, buffer, 2);
668 temp = buffer[0]*1000;
669 temp += (buffer[1] >> 6) * 250;
670
671 mutex_unlock(&applesmc_lock);
672
673 if (ret)
674 return ret;
675 else
676 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
677}
678
679static ssize_t applesmc_show_fan_speed(struct device *dev,
680 struct device_attribute *attr, char *sysfsbuf)
681{
682 int ret;
683 unsigned int speed = 0;
684 char newkey[5];
685 u8 buffer[2];
686 struct sensor_device_attribute_2 *sensor_attr =
687 to_sensor_dev_attr_2(attr);
688
689 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
690 newkey[1] = '0' + sensor_attr->index;
691 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
692 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
693 newkey[4] = 0;
694
695 mutex_lock(&applesmc_lock);
696
697 ret = applesmc_read_key(newkey, buffer, 2);
698 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
699
700 mutex_unlock(&applesmc_lock);
701 if (ret)
702 return ret;
703 else
704 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
705}
706
707static ssize_t applesmc_store_fan_speed(struct device *dev,
708 struct device_attribute *attr,
709 const char *sysfsbuf, size_t count)
710{
711 int ret;
712 u32 speed;
713 char newkey[5];
714 u8 buffer[2];
715 struct sensor_device_attribute_2 *sensor_attr =
716 to_sensor_dev_attr_2(attr);
717
718 speed = simple_strtoul(sysfsbuf, NULL, 10);
719
720 if (speed > 0x4000) /* Bigger than a 14-bit value */
721 return -EINVAL;
722
723 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
724 newkey[1] = '0' + sensor_attr->index;
725 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
726 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
727 newkey[4] = 0;
728
729 mutex_lock(&applesmc_lock);
730
731 buffer[0] = (speed >> 6) & 0xff;
732 buffer[1] = (speed << 2) & 0xff;
733 ret = applesmc_write_key(newkey, buffer, 2);
734
735 mutex_unlock(&applesmc_lock);
736 if (ret)
737 return ret;
738 else
739 return count;
740}
741
742static ssize_t applesmc_show_fan_manual(struct device *dev,
743 struct device_attribute *devattr, char *sysfsbuf)
744{
745 int ret;
746 u16 manual = 0;
747 u8 buffer[2];
748 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
749
750 mutex_lock(&applesmc_lock);
751
752 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
753 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
754
755 mutex_unlock(&applesmc_lock);
756 if (ret)
757 return ret;
758 else
759 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
760}
761
762static ssize_t applesmc_store_fan_manual(struct device *dev,
763 struct device_attribute *devattr,
764 const char *sysfsbuf, size_t count)
765{
766 int ret;
767 u8 buffer[2];
768 u32 input;
769 u16 val;
770 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
771
772 input = simple_strtoul(sysfsbuf, NULL, 10);
773
774 mutex_lock(&applesmc_lock);
775
776 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
777 val = (buffer[0] << 8 | buffer[1]);
778 if (ret)
779 goto out;
780
781 if (input)
782 val = val | (0x01 << attr->index);
783 else
784 val = val & ~(0x01 << attr->index);
785
786 buffer[0] = (val >> 8) & 0xFF;
787 buffer[1] = val & 0xFF;
788
789 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
790
791out:
792 mutex_unlock(&applesmc_lock);
793 if (ret)
794 return ret;
795 else
796 return count;
797}
798
799static ssize_t applesmc_show_fan_position(struct device *dev,
800 struct device_attribute *attr, char *sysfsbuf)
801{
802 int ret;
803 char newkey[5];
804 u8 buffer[17];
805 struct sensor_device_attribute_2 *sensor_attr =
806 to_sensor_dev_attr_2(attr);
807
808 newkey[0] = FAN_POSITION[0];
809 newkey[1] = '0' + sensor_attr->index;
810 newkey[2] = FAN_POSITION[2];
811 newkey[3] = FAN_POSITION[3];
812 newkey[4] = 0;
813
814 mutex_lock(&applesmc_lock);
815
816 ret = applesmc_read_key(newkey, buffer, 16);
817 buffer[16] = 0;
818
819 mutex_unlock(&applesmc_lock);
820 if (ret)
821 return ret;
822 else
823 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
824}
825
826static ssize_t applesmc_calibrate_show(struct device *dev,
827 struct device_attribute *attr, char *sysfsbuf)
828{
829 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
830}
831
832static ssize_t applesmc_calibrate_store(struct device *dev,
833 struct device_attribute *attr, const char *sysfsbuf, size_t count)
834{
835 mutex_lock(&applesmc_lock);
836 applesmc_calibrate();
837 mutex_unlock(&applesmc_lock);
838
839 return count;
840}
841
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700842static void applesmc_backlight_set(struct work_struct *work)
843{
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700844 mutex_lock(&applesmc_lock);
Henrik Rydberga976f152009-09-21 17:04:50 -0700845 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700846 mutex_unlock(&applesmc_lock);
847}
848static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
849
850static void applesmc_brightness_set(struct led_classdev *led_cdev,
851 enum led_brightness value)
852{
853 int ret;
854
Henrik Rydberga976f152009-09-21 17:04:50 -0700855 backlight_state[0] = value;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700856 ret = queue_work(applesmc_led_wq, &backlight_work);
857
858 if (debug && (!ret))
859 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
860}
861
862static ssize_t applesmc_key_count_show(struct device *dev,
863 struct device_attribute *attr, char *sysfsbuf)
864{
865 int ret;
866 u8 buffer[4];
867 u32 count;
868
869 mutex_lock(&applesmc_lock);
870
871 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
872 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
873 ((u32)buffer[2]<<8) + buffer[3];
874
875 mutex_unlock(&applesmc_lock);
876 if (ret)
877 return ret;
878 else
879 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
880}
881
882static ssize_t applesmc_key_at_index_read_show(struct device *dev,
883 struct device_attribute *attr, char *sysfsbuf)
884{
885 char key[5];
886 char info[6];
887 int ret;
888
889 mutex_lock(&applesmc_lock);
890
891 ret = applesmc_get_key_at_index(key_at_index, key);
892
893 if (ret || !key[0]) {
894 mutex_unlock(&applesmc_lock);
895
896 return -EINVAL;
897 }
898
899 ret = applesmc_get_key_type(key, info);
900
901 if (ret) {
902 mutex_unlock(&applesmc_lock);
903
904 return ret;
905 }
906
907 /*
908 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
909 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
910 */
911 ret = applesmc_read_key(key, sysfsbuf, info[0]);
912
913 mutex_unlock(&applesmc_lock);
914
915 if (!ret) {
916 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400917 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700918 return ret;
919 }
920}
921
922static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
923 struct device_attribute *attr, char *sysfsbuf)
924{
925 char key[5];
926 char info[6];
927 int ret;
928
929 mutex_lock(&applesmc_lock);
930
931 ret = applesmc_get_key_at_index(key_at_index, key);
932
933 if (ret || !key[0]) {
934 mutex_unlock(&applesmc_lock);
935
936 return -EINVAL;
937 }
938
939 ret = applesmc_get_key_type(key, info);
940
941 mutex_unlock(&applesmc_lock);
942
943 if (!ret)
944 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
945 else
946 return ret;
947}
948
949static ssize_t applesmc_key_at_index_type_show(struct device *dev,
950 struct device_attribute *attr, char *sysfsbuf)
951{
952 char key[5];
953 char info[6];
954 int ret;
955
956 mutex_lock(&applesmc_lock);
957
958 ret = applesmc_get_key_at_index(key_at_index, key);
959
960 if (ret || !key[0]) {
961 mutex_unlock(&applesmc_lock);
962
963 return -EINVAL;
964 }
965
966 ret = applesmc_get_key_type(key, info);
967
968 mutex_unlock(&applesmc_lock);
969
970 if (!ret)
971 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
972 else
973 return ret;
974}
975
976static ssize_t applesmc_key_at_index_name_show(struct device *dev,
977 struct device_attribute *attr, char *sysfsbuf)
978{
979 char key[5];
980 int ret;
981
982 mutex_lock(&applesmc_lock);
983
984 ret = applesmc_get_key_at_index(key_at_index, key);
985
986 mutex_unlock(&applesmc_lock);
987
988 if (!ret && key[0])
989 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
990 else
991 return -EINVAL;
992}
993
994static ssize_t applesmc_key_at_index_show(struct device *dev,
995 struct device_attribute *attr, char *sysfsbuf)
996{
997 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
998}
999
1000static ssize_t applesmc_key_at_index_store(struct device *dev,
1001 struct device_attribute *attr, const char *sysfsbuf, size_t count)
1002{
1003 mutex_lock(&applesmc_lock);
1004
1005 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
1006
1007 mutex_unlock(&applesmc_lock);
1008
1009 return count;
1010}
1011
1012static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +01001013 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001014 .default_trigger = "nand-disk",
1015 .brightness_set = applesmc_brightness_set,
1016};
1017
Nicolas Boichatfa744192007-05-23 13:58:13 -07001018static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
1019
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001020static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
1021static DEVICE_ATTR(calibrate, 0644,
1022 applesmc_calibrate_show, applesmc_calibrate_store);
1023
1024static struct attribute *accelerometer_attributes[] = {
1025 &dev_attr_position.attr,
1026 &dev_attr_calibrate.attr,
1027 NULL
1028};
1029
1030static const struct attribute_group accelerometer_attributes_group =
1031 { .attrs = accelerometer_attributes };
1032
1033static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
1034
1035static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
1036static DEVICE_ATTR(key_at_index, 0644,
1037 applesmc_key_at_index_show, applesmc_key_at_index_store);
1038static DEVICE_ATTR(key_at_index_name, 0444,
1039 applesmc_key_at_index_name_show, NULL);
1040static DEVICE_ATTR(key_at_index_type, 0444,
1041 applesmc_key_at_index_type_show, NULL);
1042static DEVICE_ATTR(key_at_index_data_length, 0444,
1043 applesmc_key_at_index_data_length_show, NULL);
1044static DEVICE_ATTR(key_at_index_data, 0444,
1045 applesmc_key_at_index_read_show, NULL);
1046
1047static struct attribute *key_enumeration_attributes[] = {
1048 &dev_attr_key_count.attr,
1049 &dev_attr_key_at_index.attr,
1050 &dev_attr_key_at_index_name.attr,
1051 &dev_attr_key_at_index_type.attr,
1052 &dev_attr_key_at_index_data_length.attr,
1053 &dev_attr_key_at_index_data.attr,
1054 NULL
1055};
1056
1057static const struct attribute_group key_enumeration_group =
1058 { .attrs = key_enumeration_attributes };
1059
1060/*
1061 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1062 * - show actual speed
1063 * - show/store minimum speed
1064 * - show maximum speed
1065 * - show safe speed
1066 * - show/store target speed
1067 * - show/store manual mode
1068 */
1069#define sysfs_fan_speeds_offset(offset) \
1070static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1071 applesmc_show_fan_speed, NULL, 0, offset-1); \
1072\
1073static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1074 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1075\
1076static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1077 applesmc_show_fan_speed, NULL, 2, offset-1); \
1078\
1079static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1080 applesmc_show_fan_speed, NULL, 3, offset-1); \
1081\
1082static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1083 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1084\
1085static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1086 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1087\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001088static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001089 applesmc_show_fan_position, NULL, offset-1); \
1090\
1091static struct attribute *fan##offset##_attributes[] = { \
1092 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1093 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1094 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1095 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1096 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1097 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001098 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001099 NULL \
1100};
1101
1102/*
1103 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001104 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001105 */
1106sysfs_fan_speeds_offset(1);
1107sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001108sysfs_fan_speeds_offset(3);
1109sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001110
1111static const struct attribute_group fan_attribute_groups[] = {
1112 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001113 { .attrs = fan2_attributes },
1114 { .attrs = fan3_attributes },
1115 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001116};
1117
1118/*
1119 * Temperature sensors sysfs entries.
1120 */
Alex Murrayfa5575c2010-05-27 19:58:54 +02001121static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
1122 applesmc_show_sensor_label, NULL, 0);
1123static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
1124 applesmc_show_sensor_label, NULL, 1);
1125static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
1126 applesmc_show_sensor_label, NULL, 2);
1127static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
1128 applesmc_show_sensor_label, NULL, 3);
1129static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
1130 applesmc_show_sensor_label, NULL, 4);
1131static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
1132 applesmc_show_sensor_label, NULL, 5);
1133static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
1134 applesmc_show_sensor_label, NULL, 6);
1135static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
1136 applesmc_show_sensor_label, NULL, 7);
1137static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
1138 applesmc_show_sensor_label, NULL, 8);
1139static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
1140 applesmc_show_sensor_label, NULL, 9);
1141static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
1142 applesmc_show_sensor_label, NULL, 10);
1143static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
1144 applesmc_show_sensor_label, NULL, 11);
1145static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
1146 applesmc_show_sensor_label, NULL, 12);
1147static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
1148 applesmc_show_sensor_label, NULL, 13);
1149static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
1150 applesmc_show_sensor_label, NULL, 14);
1151static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
1152 applesmc_show_sensor_label, NULL, 15);
1153static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
1154 applesmc_show_sensor_label, NULL, 16);
1155static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
1156 applesmc_show_sensor_label, NULL, 17);
1157static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
1158 applesmc_show_sensor_label, NULL, 18);
1159static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
1160 applesmc_show_sensor_label, NULL, 19);
1161static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
1162 applesmc_show_sensor_label, NULL, 20);
1163static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
1164 applesmc_show_sensor_label, NULL, 21);
1165static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
1166 applesmc_show_sensor_label, NULL, 22);
1167static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
1168 applesmc_show_sensor_label, NULL, 23);
1169static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
1170 applesmc_show_sensor_label, NULL, 24);
1171static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
1172 applesmc_show_sensor_label, NULL, 25);
1173static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
1174 applesmc_show_sensor_label, NULL, 26);
1175static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
1176 applesmc_show_sensor_label, NULL, 27);
1177static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
1178 applesmc_show_sensor_label, NULL, 28);
1179static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
1180 applesmc_show_sensor_label, NULL, 29);
1181static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
1182 applesmc_show_sensor_label, NULL, 30);
1183static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
1184 applesmc_show_sensor_label, NULL, 31);
1185static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
1186 applesmc_show_sensor_label, NULL, 32);
1187static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
1188 applesmc_show_sensor_label, NULL, 33);
1189static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
1190 applesmc_show_sensor_label, NULL, 34);
1191static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
1192 applesmc_show_sensor_label, NULL, 35);
1193static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
1194 applesmc_show_sensor_label, NULL, 36);
1195static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
1196 applesmc_show_sensor_label, NULL, 37);
1197static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
1198 applesmc_show_sensor_label, NULL, 38);
1199static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
1200 applesmc_show_sensor_label, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001201static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1202 applesmc_show_temperature, NULL, 0);
1203static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1204 applesmc_show_temperature, NULL, 1);
1205static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1206 applesmc_show_temperature, NULL, 2);
1207static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1208 applesmc_show_temperature, NULL, 3);
1209static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1210 applesmc_show_temperature, NULL, 4);
1211static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1212 applesmc_show_temperature, NULL, 5);
1213static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1214 applesmc_show_temperature, NULL, 6);
1215static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1216 applesmc_show_temperature, NULL, 7);
1217static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1218 applesmc_show_temperature, NULL, 8);
1219static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1220 applesmc_show_temperature, NULL, 9);
1221static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1222 applesmc_show_temperature, NULL, 10);
1223static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1224 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001225static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1226 applesmc_show_temperature, NULL, 12);
1227static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1228 applesmc_show_temperature, NULL, 13);
1229static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1230 applesmc_show_temperature, NULL, 14);
1231static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1232 applesmc_show_temperature, NULL, 15);
1233static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1234 applesmc_show_temperature, NULL, 16);
1235static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1236 applesmc_show_temperature, NULL, 17);
1237static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1238 applesmc_show_temperature, NULL, 18);
1239static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1240 applesmc_show_temperature, NULL, 19);
1241static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1242 applesmc_show_temperature, NULL, 20);
1243static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1244 applesmc_show_temperature, NULL, 21);
1245static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1246 applesmc_show_temperature, NULL, 22);
1247static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1248 applesmc_show_temperature, NULL, 23);
1249static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1250 applesmc_show_temperature, NULL, 24);
1251static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1252 applesmc_show_temperature, NULL, 25);
1253static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1254 applesmc_show_temperature, NULL, 26);
1255static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1256 applesmc_show_temperature, NULL, 27);
1257static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1258 applesmc_show_temperature, NULL, 28);
1259static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1260 applesmc_show_temperature, NULL, 29);
1261static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1262 applesmc_show_temperature, NULL, 30);
1263static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1264 applesmc_show_temperature, NULL, 31);
1265static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1266 applesmc_show_temperature, NULL, 32);
1267static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1268 applesmc_show_temperature, NULL, 33);
1269static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1270 applesmc_show_temperature, NULL, 34);
Bharath Rameshfb9f88e12009-01-29 14:25:24 -08001271static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
1272 applesmc_show_temperature, NULL, 35);
1273static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
1274 applesmc_show_temperature, NULL, 36);
1275static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
1276 applesmc_show_temperature, NULL, 37);
1277static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
1278 applesmc_show_temperature, NULL, 38);
1279static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
1280 applesmc_show_temperature, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001281
Alex Murrayfa5575c2010-05-27 19:58:54 +02001282static struct attribute *label_attributes[] = {
1283 &sensor_dev_attr_temp1_label.dev_attr.attr,
1284 &sensor_dev_attr_temp2_label.dev_attr.attr,
1285 &sensor_dev_attr_temp3_label.dev_attr.attr,
1286 &sensor_dev_attr_temp4_label.dev_attr.attr,
1287 &sensor_dev_attr_temp5_label.dev_attr.attr,
1288 &sensor_dev_attr_temp6_label.dev_attr.attr,
1289 &sensor_dev_attr_temp7_label.dev_attr.attr,
1290 &sensor_dev_attr_temp8_label.dev_attr.attr,
1291 &sensor_dev_attr_temp9_label.dev_attr.attr,
1292 &sensor_dev_attr_temp10_label.dev_attr.attr,
1293 &sensor_dev_attr_temp11_label.dev_attr.attr,
1294 &sensor_dev_attr_temp12_label.dev_attr.attr,
1295 &sensor_dev_attr_temp13_label.dev_attr.attr,
1296 &sensor_dev_attr_temp14_label.dev_attr.attr,
1297 &sensor_dev_attr_temp15_label.dev_attr.attr,
1298 &sensor_dev_attr_temp16_label.dev_attr.attr,
1299 &sensor_dev_attr_temp17_label.dev_attr.attr,
1300 &sensor_dev_attr_temp18_label.dev_attr.attr,
1301 &sensor_dev_attr_temp19_label.dev_attr.attr,
1302 &sensor_dev_attr_temp20_label.dev_attr.attr,
1303 &sensor_dev_attr_temp21_label.dev_attr.attr,
1304 &sensor_dev_attr_temp22_label.dev_attr.attr,
1305 &sensor_dev_attr_temp23_label.dev_attr.attr,
1306 &sensor_dev_attr_temp24_label.dev_attr.attr,
1307 &sensor_dev_attr_temp25_label.dev_attr.attr,
1308 &sensor_dev_attr_temp26_label.dev_attr.attr,
1309 &sensor_dev_attr_temp27_label.dev_attr.attr,
1310 &sensor_dev_attr_temp28_label.dev_attr.attr,
1311 &sensor_dev_attr_temp29_label.dev_attr.attr,
1312 &sensor_dev_attr_temp30_label.dev_attr.attr,
1313 &sensor_dev_attr_temp31_label.dev_attr.attr,
1314 &sensor_dev_attr_temp32_label.dev_attr.attr,
1315 &sensor_dev_attr_temp33_label.dev_attr.attr,
1316 &sensor_dev_attr_temp34_label.dev_attr.attr,
1317 &sensor_dev_attr_temp35_label.dev_attr.attr,
1318 &sensor_dev_attr_temp36_label.dev_attr.attr,
1319 &sensor_dev_attr_temp37_label.dev_attr.attr,
1320 &sensor_dev_attr_temp38_label.dev_attr.attr,
1321 &sensor_dev_attr_temp39_label.dev_attr.attr,
1322 &sensor_dev_attr_temp40_label.dev_attr.attr,
1323 NULL
1324};
1325
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001326static struct attribute *temperature_attributes[] = {
1327 &sensor_dev_attr_temp1_input.dev_attr.attr,
1328 &sensor_dev_attr_temp2_input.dev_attr.attr,
1329 &sensor_dev_attr_temp3_input.dev_attr.attr,
1330 &sensor_dev_attr_temp4_input.dev_attr.attr,
1331 &sensor_dev_attr_temp5_input.dev_attr.attr,
1332 &sensor_dev_attr_temp6_input.dev_attr.attr,
1333 &sensor_dev_attr_temp7_input.dev_attr.attr,
1334 &sensor_dev_attr_temp8_input.dev_attr.attr,
1335 &sensor_dev_attr_temp9_input.dev_attr.attr,
1336 &sensor_dev_attr_temp10_input.dev_attr.attr,
1337 &sensor_dev_attr_temp11_input.dev_attr.attr,
1338 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001339 &sensor_dev_attr_temp13_input.dev_attr.attr,
1340 &sensor_dev_attr_temp14_input.dev_attr.attr,
1341 &sensor_dev_attr_temp15_input.dev_attr.attr,
1342 &sensor_dev_attr_temp16_input.dev_attr.attr,
1343 &sensor_dev_attr_temp17_input.dev_attr.attr,
1344 &sensor_dev_attr_temp18_input.dev_attr.attr,
1345 &sensor_dev_attr_temp19_input.dev_attr.attr,
1346 &sensor_dev_attr_temp20_input.dev_attr.attr,
1347 &sensor_dev_attr_temp21_input.dev_attr.attr,
1348 &sensor_dev_attr_temp22_input.dev_attr.attr,
1349 &sensor_dev_attr_temp23_input.dev_attr.attr,
1350 &sensor_dev_attr_temp24_input.dev_attr.attr,
1351 &sensor_dev_attr_temp25_input.dev_attr.attr,
1352 &sensor_dev_attr_temp26_input.dev_attr.attr,
1353 &sensor_dev_attr_temp27_input.dev_attr.attr,
1354 &sensor_dev_attr_temp28_input.dev_attr.attr,
1355 &sensor_dev_attr_temp29_input.dev_attr.attr,
1356 &sensor_dev_attr_temp30_input.dev_attr.attr,
1357 &sensor_dev_attr_temp31_input.dev_attr.attr,
1358 &sensor_dev_attr_temp32_input.dev_attr.attr,
1359 &sensor_dev_attr_temp33_input.dev_attr.attr,
1360 &sensor_dev_attr_temp34_input.dev_attr.attr,
1361 &sensor_dev_attr_temp35_input.dev_attr.attr,
Bharath Rameshfb9f88e12009-01-29 14:25:24 -08001362 &sensor_dev_attr_temp36_input.dev_attr.attr,
1363 &sensor_dev_attr_temp37_input.dev_attr.attr,
1364 &sensor_dev_attr_temp38_input.dev_attr.attr,
1365 &sensor_dev_attr_temp39_input.dev_attr.attr,
1366 &sensor_dev_attr_temp40_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001367 NULL
1368};
1369
1370static const struct attribute_group temperature_attributes_group =
1371 { .attrs = temperature_attributes };
1372
Alex Murrayfa5575c2010-05-27 19:58:54 +02001373static const struct attribute_group label_attributes_group = {
1374 .attrs = label_attributes
1375};
1376
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001377/* Module stuff */
1378
1379/*
1380 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1381 */
Jeff Garzik18552562007-10-03 15:15:40 -04001382static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001383{
1384 int i = 0;
1385 struct dmi_match_data* dmi_data = id->driver_data;
1386 printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
1387 applesmc_accelerometer = dmi_data->accelerometer;
1388 printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
1389 applesmc_accelerometer ? "with" : "without");
1390 applesmc_light = dmi_data->light;
1391 printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
1392 applesmc_light ? "with" : "without");
1393
1394 applesmc_temperature_set = dmi_data->temperature_set;
1395 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1396 i++;
1397 printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
1398 return 1;
1399}
1400
1401/* Create accelerometer ressources */
1402static int applesmc_create_accelerometer(void)
1403{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001404 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001405 int ret;
1406
1407 ret = sysfs_create_group(&pdev->dev.kobj,
1408 &accelerometer_attributes_group);
1409 if (ret)
1410 goto out;
1411
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001412 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001413 if (!applesmc_idev) {
1414 ret = -ENOMEM;
1415 goto out_sysfs;
1416 }
1417
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001418 applesmc_idev->poll = applesmc_idev_poll;
1419 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1420
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001421 /* initial calibrate for the input device */
1422 applesmc_calibrate();
1423
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001424 /* initialize the input device */
1425 idev = applesmc_idev->input;
1426 idev->name = "applesmc";
1427 idev->id.bustype = BUS_HOST;
1428 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001429 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001430 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001431 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001432 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001433 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1434
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001435 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001436 if (ret)
1437 goto out_idev;
1438
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001439 return 0;
1440
1441out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001442 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001443
1444out_sysfs:
1445 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1446
1447out:
1448 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1449 return ret;
1450}
1451
1452/* Release all ressources used by the accelerometer */
1453static void applesmc_release_accelerometer(void)
1454{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001455 input_unregister_polled_device(applesmc_idev);
1456 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001457 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1458}
1459
1460static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1461/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1462 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001463/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001464 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001465/* MacBook: accelerometer and temperature set 2 */
1466 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1467/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001468 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001469/* MacPro: temperature set 4 */
1470 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001471/* iMac: temperature set 5 */
1472 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Henrik Rydberg468cc032008-11-12 13:24:58 -08001473/* MacBook3, MacBook4: accelerometer and temperature set 6 */
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001474 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001475/* MacBook Air: accelerometer, backlight and temperature set 7 */
1476 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001477/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1478 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001479/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1480 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001481/* iMac 5: light sensor only, temperature set 10 */
1482 { .accelerometer = 0, .light = 0, .temperature_set = 10 },
Henrik Rydberg181209a2008-11-06 12:53:20 -08001483/* MacBook 5: accelerometer, backlight and temperature set 11 */
1484 { .accelerometer = 1, .light = 1, .temperature_set = 11 },
Henrik Rydberga6660322008-11-06 12:53:21 -08001485/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
1486 { .accelerometer = 1, .light = 1, .temperature_set = 12 },
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001487/* iMac 8: light sensor only, temperature set 13 */
1488 { .accelerometer = 0, .light = 0, .temperature_set = 13 },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001489/* iMac 6: light sensor only, temperature set 14 */
1490 { .accelerometer = 0, .light = 0, .temperature_set = 14 },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001491/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
1492 { .accelerometer = 1, .light = 1, .temperature_set = 15 },
Bharath Rameshfb9f88e12009-01-29 14:25:24 -08001493/* MacPro3,1: temperature set 16 */
1494 { .accelerometer = 0, .light = 0, .temperature_set = 16 },
Justin P. Mattocke1741712010-04-14 16:14:10 +02001495/* iMac 9,1: light sensor only, temperature set 17 */
1496 { .accelerometer = 0, .light = 0, .temperature_set = 17 },
1497/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
1498 { .accelerometer = 1, .light = 1, .temperature_set = 18 },
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +02001499/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
1500 { .accelerometer = 1, .light = 1, .temperature_set = 19 },
1501/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
1502 { .accelerometer = 1, .light = 1, .temperature_set = 20 },
Bernhard Froemel872bad52010-05-27 19:58:52 +02001503/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
1504 { .accelerometer = 1, .light = 1, .temperature_set = 21 },
Henrik Rydberg405eaa12010-05-27 19:58:53 +02001505/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
1506 { .accelerometer = 1, .light = 1, .temperature_set = 22 },
Edgar Hucek132af032010-11-09 15:15:01 +00001507/* MacBook Air 3,1: accelerometer, backlight and temperature set 23 */
1508 { .accelerometer = 0, .light = 0, .temperature_set = 23 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001509};
1510
1511/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1512 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1513static __initdata struct dmi_system_id applesmc_whitelist[] = {
Edgar Hucek132af032010-11-09 15:15:01 +00001514 { applesmc_dmi_match, "Apple MacBook Air 3", {
1515 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1516 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3") },
1517 &applesmc_dmi_data[23]},
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001518 { applesmc_dmi_match, "Apple MacBook Air 2", {
1519 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1520 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
1521 &applesmc_dmi_data[15]},
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001522 { applesmc_dmi_match, "Apple MacBook Air", {
1523 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1524 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001525 &applesmc_dmi_data[7]},
Henrik Rydberg405eaa12010-05-27 19:58:53 +02001526 { applesmc_dmi_match, "Apple MacBook Pro 7", {
1527 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1528 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
1529 &applesmc_dmi_data[22]},
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +02001530 { applesmc_dmi_match, "Apple MacBook Pro 5,4", {
1531 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1532 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
1533 &applesmc_dmi_data[20]},
1534 { applesmc_dmi_match, "Apple MacBook Pro 5,3", {
1535 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1536 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
1537 &applesmc_dmi_data[19]},
Bernhard Froemel872bad52010-05-27 19:58:52 +02001538 { applesmc_dmi_match, "Apple MacBook Pro 6", {
1539 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1540 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
1541 &applesmc_dmi_data[21]},
Henrik Rydberga6660322008-11-06 12:53:21 -08001542 { applesmc_dmi_match, "Apple MacBook Pro 5", {
1543 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1544 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
1545 &applesmc_dmi_data[12]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001546 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1547 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1548 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1549 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001550 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1551 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1552 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1553 &applesmc_dmi_data[9]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001554 { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
1555 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
1556 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
1557 &applesmc_dmi_data[18]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001558 { applesmc_dmi_match, "Apple MacBook Pro", {
1559 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1560 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001561 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001562 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001563 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001564 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001565 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001566 { applesmc_dmi_match, "Apple MacBook (v3)", {
1567 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1568 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001569 &applesmc_dmi_data[6]},
Henrik Rydberg468cc032008-11-12 13:24:58 -08001570 { applesmc_dmi_match, "Apple MacBook 4", {
1571 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1572 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
1573 &applesmc_dmi_data[6]},
Henrik Rydberg181209a2008-11-06 12:53:20 -08001574 { applesmc_dmi_match, "Apple MacBook 5", {
1575 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1576 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
1577 &applesmc_dmi_data[11]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001578 { applesmc_dmi_match, "Apple MacBook", {
1579 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1580 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001581 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001582 { applesmc_dmi_match, "Apple Macmini", {
1583 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1584 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001585 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001586 { applesmc_dmi_match, "Apple MacPro2", {
1587 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1588 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001589 &applesmc_dmi_data[4]},
Bharath Rameshfb9f88e12009-01-29 14:25:24 -08001590 { applesmc_dmi_match, "Apple MacPro3", {
1591 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1592 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
1593 &applesmc_dmi_data[16]},
Henrik Rydberg45a3a362008-11-19 15:36:42 -08001594 { applesmc_dmi_match, "Apple MacPro", {
1595 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1596 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1597 &applesmc_dmi_data[4]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001598 { applesmc_dmi_match, "Apple iMac 9,1", {
1599 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
1600 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
1601 &applesmc_dmi_data[17]},
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001602 { applesmc_dmi_match, "Apple iMac 8", {
1603 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1604 DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
1605 &applesmc_dmi_data[13]},
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001606 { applesmc_dmi_match, "Apple iMac 6", {
1607 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1608 DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
1609 &applesmc_dmi_data[14]},
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001610 { applesmc_dmi_match, "Apple iMac 5", {
1611 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1612 DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
1613 &applesmc_dmi_data[10]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001614 { applesmc_dmi_match, "Apple iMac", {
1615 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1616 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001617 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001618 { .ident = NULL }
1619};
1620
1621static int __init applesmc_init(void)
1622{
1623 int ret;
1624 int count;
1625 int i;
1626
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001627 if (!dmi_check_system(applesmc_whitelist)) {
1628 printk(KERN_WARNING "applesmc: supported laptop not found!\n");
1629 ret = -ENODEV;
1630 goto out;
1631 }
1632
1633 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1634 "applesmc")) {
1635 ret = -ENXIO;
1636 goto out;
1637 }
1638
1639 ret = platform_driver_register(&applesmc_driver);
1640 if (ret)
1641 goto out_region;
1642
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001643 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1644 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001645 if (IS_ERR(pdev)) {
1646 ret = PTR_ERR(pdev);
1647 goto out_driver;
1648 }
1649
Nicolas Boichatfa744192007-05-23 13:58:13 -07001650 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001651 if (ret)
1652 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001653
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001654 /* Create key enumeration sysfs files */
1655 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1656 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001657 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001658
1659 /* create fan files */
1660 count = applesmc_get_fan_count();
Henrik Rydberg0559a532010-05-11 09:17:47 +02001661 if (count < 0)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001662 printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
Henrik Rydberg0559a532010-05-11 09:17:47 +02001663 else
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001664 printk(KERN_INFO "applesmc: %d fans found.\n", count);
1665
Henrik Rydberg0559a532010-05-11 09:17:47 +02001666 if (count > 4) {
1667 count = 4;
1668 printk(KERN_WARNING "applesmc: More than 4 fans found,"
1669 " but at most 4 fans are supported"
1670 " by the driver.\n");
1671 }
1672
1673 while (fans_handled < count) {
1674 ret = sysfs_create_group(&pdev->dev.kobj,
1675 &fan_attribute_groups[fans_handled]);
1676 if (ret)
1677 goto out_fans;
1678 fans_handled++;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001679 }
1680
1681 for (i = 0;
1682 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1683 i++) {
Alex Murrayfa5575c2010-05-27 19:58:54 +02001684 if (temperature_attributes[i] == NULL ||
1685 label_attributes[i] == NULL) {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001686 printk(KERN_ERR "applesmc: More temperature sensors "
1687 "in temperature_sensors_sets (at least %i)"
1688 "than available sysfs files in "
1689 "temperature_attributes (%i), please report "
1690 "this bug.\n", i, i-1);
1691 goto out_temperature;
1692 }
1693 ret = sysfs_create_file(&pdev->dev.kobj,
1694 temperature_attributes[i]);
1695 if (ret)
1696 goto out_temperature;
Alex Murrayfa5575c2010-05-27 19:58:54 +02001697 ret = sysfs_create_file(&pdev->dev.kobj,
1698 label_attributes[i]);
1699 if (ret)
1700 goto out_temperature;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001701 }
1702
1703 if (applesmc_accelerometer) {
1704 ret = applesmc_create_accelerometer();
1705 if (ret)
1706 goto out_temperature;
1707 }
1708
1709 if (applesmc_light) {
1710 /* Add light sensor file */
1711 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1712 if (ret)
1713 goto out_accelerometer;
1714
1715 /* Create the workqueue */
1716 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1717 if (!applesmc_led_wq) {
1718 ret = -ENOMEM;
1719 goto out_light_sysfs;
1720 }
1721
1722 /* register as a led device */
1723 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1724 if (ret < 0)
1725 goto out_light_wq;
1726 }
1727
Tony Jones1beeffe2007-08-20 13:46:20 -07001728 hwmon_dev = hwmon_device_register(&pdev->dev);
1729 if (IS_ERR(hwmon_dev)) {
1730 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001731 goto out_light_ledclass;
1732 }
1733
1734 printk(KERN_INFO "applesmc: driver successfully loaded.\n");
1735
1736 return 0;
1737
1738out_light_ledclass:
1739 if (applesmc_light)
1740 led_classdev_unregister(&applesmc_backlight);
1741out_light_wq:
1742 if (applesmc_light)
1743 destroy_workqueue(applesmc_led_wq);
1744out_light_sysfs:
1745 if (applesmc_light)
1746 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1747out_accelerometer:
1748 if (applesmc_accelerometer)
1749 applesmc_release_accelerometer();
1750out_temperature:
Alex Murrayfa5575c2010-05-27 19:58:54 +02001751 sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001752 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
Henrik Rydberg0559a532010-05-11 09:17:47 +02001753out_fans:
1754 while (fans_handled)
1755 sysfs_remove_group(&pdev->dev.kobj,
1756 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001757 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001758out_name:
1759 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001760out_device:
1761 platform_device_unregister(pdev);
1762out_driver:
1763 platform_driver_unregister(&applesmc_driver);
1764out_region:
1765 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1766out:
1767 printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
1768 return ret;
1769}
1770
1771static void __exit applesmc_exit(void)
1772{
Tony Jones1beeffe2007-08-20 13:46:20 -07001773 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001774 if (applesmc_light) {
1775 led_classdev_unregister(&applesmc_backlight);
1776 destroy_workqueue(applesmc_led_wq);
1777 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1778 }
1779 if (applesmc_accelerometer)
1780 applesmc_release_accelerometer();
Alex Murrayfa5575c2010-05-27 19:58:54 +02001781 sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001782 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
Henrik Rydberg0559a532010-05-11 09:17:47 +02001783 while (fans_handled)
1784 sysfs_remove_group(&pdev->dev.kobj,
1785 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001786 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001787 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001788 platform_device_unregister(pdev);
1789 platform_driver_unregister(&applesmc_driver);
1790 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1791
1792 printk(KERN_INFO "applesmc: driver unloaded.\n");
1793}
1794
1795module_init(applesmc_init);
1796module_exit(applesmc_exit);
1797
1798MODULE_AUTHOR("Nicolas Boichat");
1799MODULE_DESCRIPTION("Apple SMC");
1800MODULE_LICENSE("GPL v2");
Henrik Rydbergdc924ef2008-12-01 13:13:49 -08001801MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);