blob: 5f67e390e45cb64ea6f2407d6bb81053e6fa162b [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
Joe Perches1ee7c712010-11-09 15:15:03 +000029#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070031#include <linux/delay.h>
32#include <linux/platform_device.h>
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040033#include <linux/input-polldev.h>
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070034#include <linux/kernel.h>
35#include <linux/module.h>
36#include <linux/timer.h>
37#include <linux/dmi.h>
38#include <linux/mutex.h>
39#include <linux/hwmon-sysfs.h>
H Hartley Sweeten6055fae2009-09-15 17:18:13 +020040#include <linux/io.h>
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070041#include <linux/leds.h>
42#include <linux/hwmon.h>
43#include <linux/workqueue.h>
44
45/* data port used by Apple SMC */
46#define APPLESMC_DATA_PORT 0x300
47/* command/status port used by Apple SMC */
48#define APPLESMC_CMD_PORT 0x304
49
50#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
51
52#define APPLESMC_MAX_DATA_LENGTH 32
53
Henrik Rydberg8c9398d2008-10-18 20:27:43 -070054#define APPLESMC_MIN_WAIT 0x0040
55#define APPLESMC_MAX_WAIT 0x8000
56
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070057#define APPLESMC_STATUS_MASK 0x0f
58#define APPLESMC_READ_CMD 0x10
59#define APPLESMC_WRITE_CMD 0x11
60#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
61#define APPLESMC_GET_KEY_TYPE_CMD 0x13
62
63#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */
64
Henrik Rydberg8bd1a122008-10-18 20:27:39 -070065#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6-10 bytes) */
66#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6-10 bytes) */
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040067#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070068
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -040069#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070070
71#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
72#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
73#define MOTION_SENSOR_Z_KEY "MO_Z" /* r-o sp78 (2 bytes) */
74#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */
75
76#define FANS_COUNT "FNum" /* r-o ui8 */
77#define FANS_MANUAL "FS! " /* r-w ui16 */
78#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
79#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
80#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
81#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
82#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
83#define FAN_POSITION "F0ID" /* r-o char[16] */
84
85/*
86 * Temperature sensors keys (sp78 - 2 bytes).
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070087 */
Bharath Rameshfb9f88e2009-01-29 14:25:24 -080088static const char *temperature_sensors_sets[][41] = {
Martin Szulecki1bed24b2007-07-09 11:41:36 -070089/* Set 0: Macbook Pro */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -070090 { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
91 "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080092/* Set 1: Macbook2 set */
93 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
94 "Th0S", "Th1H", NULL },
95/* Set 2: Macbook set */
Martin Szulecki1bed24b2007-07-09 11:41:36 -070096 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
97 "Th1H", "Ts0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -080098/* Set 3: Macmini set */
René Rebe8de57702007-10-16 14:19:20 -070099 { "TC0D", "TC0P", NULL },
Riki Oktariantocd19ba12008-02-04 23:41:58 -0800100/* Set 4: Mac Pro (2 x Quad-Core) */
René Rebe8de57702007-10-16 14:19:20 -0700101 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
102 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
103 "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
104 "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
105 "TM9S", "TN0H", "TS0C", NULL },
Roberto De Ioris9f86f282008-08-15 00:40:30 -0700106/* Set 5: iMac */
107 { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
108 "Tp0C", NULL },
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -0700109/* Set 6: Macbook3 set */
110 { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
111 "Th0S", "Th1H", NULL },
Henrik Rydbergf5274c92008-10-18 20:27:40 -0700112/* Set 7: Macbook Air */
113 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
114 "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
Henrik Rydbergd7549902008-10-18 20:27:41 -0700115/* Set 8: Macbook Pro 4,1 (Penryn) */
116 { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
117 "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -0700118/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
119 { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
120 "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -0800121/* Set 10: iMac 5,1 */
122 { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL },
Henrik Rydberg181209a2008-11-06 12:53:20 -0800123/* Set 11: Macbook 5,1 */
124 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P",
125 "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL },
Henrik Rydberga6660322008-11-06 12:53:21 -0800126/* Set 12: Macbook Pro 5,1 */
127 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
128 "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0",
129 "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL },
Henrik Rydbergeefc4882008-11-06 12:53:22 -0800130/* Set 13: iMac 8,1 */
131 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
132 "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -0800133/* Set 14: iMac 6,1 */
134 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
135 "TO0P", "Tp0P", NULL },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -0800136/* Set 15: MacBook Air 2,1 */
137 { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0",
138 "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P",
139 "Ts0S", NULL },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -0800140/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */
141 { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
142 "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P",
143 "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P",
144 "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S",
145 "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S",
146 NULL },
Justin P. Mattocke1741712010-04-14 16:14:10 +0200147/* Set 17: iMac 9,1 */
148 { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TH0P", "TL0P",
149 "TN0D", "TN0H", "TN0P", "TO0P", "Tm0P", "Tp0P", NULL },
150/* Set 18: MacBook Pro 2,2 */
151 { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
152 "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +0200153/* Set 19: Macbook Pro 5,3 */
154 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
155 "TG0F", "TG0H", "TG0P", "TG0T", "TN0D", "TN0P", "TTF0", "Th2H",
156 "Tm0P", "Ts0P", "Ts0S", NULL },
157/* Set 20: MacBook Pro 5,4 */
158 { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TN0D",
159 "TN0P", "TTF0", "Th2H", "Ts0P", "Ts0S", NULL },
Bernhard Froemel872bad52010-05-27 19:58:52 +0200160/* Set 21: MacBook Pro 6,2 */
161 { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", "TC0P", "TC1C", "TG0D",
162 "TG0P", "TG0T", "TMCD", "TP0P", "TPCD", "Th1H", "Th2H", "Tm0P",
163 "Ts0P", "Ts0S", NULL },
Henrik Rydberg405eaa12010-05-27 19:58:53 +0200164/* Set 22: MacBook Pro 7,1 */
165 { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", "TN0D", "TN0P", "TN0S",
166 "TN1D", "TN1F", "TN1G", "TN1S", "Th1H", "Ts0P", "Ts0S", NULL },
Edgar Hucek132af032010-11-09 15:15:01 +0000167/* Set 23: MacBook Air 3,1 */
168 { "TB0T", "TB1T", "TB2T", "TC0D", "TC0E", "TC0P", "TC1E", "TCZ3",
169 "TCZ4", "TCZ5", "TG0E", "TG1E", "TG2E", "TGZ3", "TGZ4", "TGZ5",
170 "TH0F", "TH0O", "TM0P" },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700171};
172
173/* List of keys used to read/write fan speeds */
174static const char* fan_speed_keys[] = {
175 FAN_ACTUAL_SPEED,
176 FAN_MIN_SPEED,
177 FAN_MAX_SPEED,
178 FAN_SAFE_SPEED,
179 FAN_TARGET_SPEED
180};
181
182#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
183#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
184
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400185#define APPLESMC_POLL_INTERVAL 50 /* msecs */
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700186#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
187#define APPLESMC_INPUT_FLAT 4
188
189#define SENSOR_X 0
190#define SENSOR_Y 1
191#define SENSOR_Z 2
192
193/* Structure to be passed to DMI_MATCH function */
194struct dmi_match_data {
195/* Indicates whether this computer has an accelerometer. */
196 int accelerometer;
197/* Indicates whether this computer has light sensors and keyboard backlight. */
198 int light;
199/* Indicates which temperature sensors set to use. */
200 int temperature_set;
201};
202
203static const int debug;
204static struct platform_device *pdev;
205static s16 rest_x;
206static s16 rest_y;
Henrik Rydberga976f152009-09-21 17:04:50 -0700207static u8 backlight_state[2];
208
Tony Jones1beeffe2007-08-20 13:46:20 -0700209static struct device *hwmon_dev;
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400210static struct input_polled_dev *applesmc_idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700211
212/* Indicates whether this computer has an accelerometer. */
213static unsigned int applesmc_accelerometer;
214
215/* Indicates whether this computer has light sensors and keyboard backlight. */
216static unsigned int applesmc_light;
217
Henrik Rydberg0559a532010-05-11 09:17:47 +0200218/* The number of fans handled by the driver */
219static unsigned int fans_handled;
220
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700221/* Indicates which temperature sensors set to use. */
222static unsigned int applesmc_temperature_set;
223
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400224static DEFINE_MUTEX(applesmc_lock);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700225
226/*
227 * Last index written to key_at_index sysfs file, and value to use for all other
228 * key_at_index_* sysfs files.
229 */
230static unsigned int key_at_index;
231
232static struct workqueue_struct *applesmc_led_wq;
233
234/*
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700235 * __wait_status - Wait up to 32ms for the status port to get a certain value
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700236 * (masked with 0x0f), returning zero if the value is obtained. Callers must
237 * hold applesmc_lock.
238 */
239static int __wait_status(u8 val)
240{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700241 int us;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700242
243 val = val & APPLESMC_STATUS_MASK;
244
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700245 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
246 udelay(us);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700247 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
248 if (debug)
249 printk(KERN_DEBUG
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700250 "Waited %d us for status %x\n",
251 2 * us - APPLESMC_MIN_WAIT, val);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700252 return 0;
253 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700254 }
255
Joe Perches1ee7c712010-11-09 15:15:03 +0000256 pr_warn("wait status failed: %x != %x\n", val, inb(APPLESMC_CMD_PORT));
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700257
258 return -EIO;
259}
260
261/*
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700262 * special treatment of command port - on newer macbooks, it seems necessary
263 * to resend the command byte before polling the status again. Callers must
264 * hold applesmc_lock.
265 */
266static int send_command(u8 cmd)
267{
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700268 int us;
269 for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700270 outb(cmd, APPLESMC_CMD_PORT);
Henrik Rydberg8c9398d2008-10-18 20:27:43 -0700271 udelay(us);
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700272 if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
273 return 0;
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700274 }
Joe Perches1ee7c712010-11-09 15:15:03 +0000275 pr_warn("command failed: %x -> %x\n", cmd, inb(APPLESMC_CMD_PORT));
Henrik Rydberg84d2d7f2008-10-18 20:27:38 -0700276 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) {
Joe Perches1ee7c712010-11-09 15:15:03 +0000289 pr_err("%s(): cannot read more than %d bytes\n",
290 __func__, APPLESMC_MAX_DATA_LENGTH);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700291 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) {
Joe Perches1ee7c712010-11-09 15:15:03 +0000332 pr_err("%s(): cannot write more than %d bytes\n",
333 __func__, APPLESMC_MAX_DATA_LENGTH);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700334 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
Joe Perches1ee7c712010-11-09 15:15:03 +0000473 pr_warn("failed to init the device\n");
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700474
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);
Joe Perches1ee7c712010-11-09 15:15:03 +0000619 pr_info("light sensor data length set to %d\n", data_length);
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700620 }
621
622 ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
Alex Murrayc3d63622009-01-15 13:51:08 -0800623 /* newer macbooks report a single 10-bit bigendian value */
624 if (data_length == 10) {
625 left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
626 goto out;
627 }
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700628 left = buffer[2];
629 if (ret)
630 goto out;
Henrik Rydberg8bd1a122008-10-18 20:27:39 -0700631 ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700632 right = buffer[2];
633
634out:
635 mutex_unlock(&applesmc_lock);
636 if (ret)
637 return ret;
638 else
639 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
640}
641
Alex Murrayfa5575c2010-05-27 19:58:54 +0200642/* Displays sensor key as label */
643static ssize_t applesmc_show_sensor_label(struct device *dev,
644 struct device_attribute *devattr, char *sysfsbuf)
645{
646 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
647 const char *key =
648 temperature_sensors_sets[applesmc_temperature_set][attr->index];
649
650 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
651}
652
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700653/* Displays degree Celsius * 1000 */
654static ssize_t applesmc_show_temperature(struct device *dev,
655 struct device_attribute *devattr, char *sysfsbuf)
656{
657 int ret;
658 u8 buffer[2];
659 unsigned int temp;
660 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
661 const char* key =
662 temperature_sensors_sets[applesmc_temperature_set][attr->index];
663
664 mutex_lock(&applesmc_lock);
665
666 ret = applesmc_read_key(key, buffer, 2);
667 temp = buffer[0]*1000;
668 temp += (buffer[1] >> 6) * 250;
669
670 mutex_unlock(&applesmc_lock);
671
672 if (ret)
673 return ret;
674 else
675 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
676}
677
678static ssize_t applesmc_show_fan_speed(struct device *dev,
679 struct device_attribute *attr, char *sysfsbuf)
680{
681 int ret;
682 unsigned int speed = 0;
683 char newkey[5];
684 u8 buffer[2];
685 struct sensor_device_attribute_2 *sensor_attr =
686 to_sensor_dev_attr_2(attr);
687
688 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
689 newkey[1] = '0' + sensor_attr->index;
690 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
691 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
692 newkey[4] = 0;
693
694 mutex_lock(&applesmc_lock);
695
696 ret = applesmc_read_key(newkey, buffer, 2);
697 speed = ((buffer[0] << 8 | buffer[1]) >> 2);
698
699 mutex_unlock(&applesmc_lock);
700 if (ret)
701 return ret;
702 else
703 return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
704}
705
706static ssize_t applesmc_store_fan_speed(struct device *dev,
707 struct device_attribute *attr,
708 const char *sysfsbuf, size_t count)
709{
710 int ret;
711 u32 speed;
712 char newkey[5];
713 u8 buffer[2];
714 struct sensor_device_attribute_2 *sensor_attr =
715 to_sensor_dev_attr_2(attr);
716
717 speed = simple_strtoul(sysfsbuf, NULL, 10);
718
719 if (speed > 0x4000) /* Bigger than a 14-bit value */
720 return -EINVAL;
721
722 newkey[0] = fan_speed_keys[sensor_attr->nr][0];
723 newkey[1] = '0' + sensor_attr->index;
724 newkey[2] = fan_speed_keys[sensor_attr->nr][2];
725 newkey[3] = fan_speed_keys[sensor_attr->nr][3];
726 newkey[4] = 0;
727
728 mutex_lock(&applesmc_lock);
729
730 buffer[0] = (speed >> 6) & 0xff;
731 buffer[1] = (speed << 2) & 0xff;
732 ret = applesmc_write_key(newkey, buffer, 2);
733
734 mutex_unlock(&applesmc_lock);
735 if (ret)
736 return ret;
737 else
738 return count;
739}
740
741static ssize_t applesmc_show_fan_manual(struct device *dev,
742 struct device_attribute *devattr, char *sysfsbuf)
743{
744 int ret;
745 u16 manual = 0;
746 u8 buffer[2];
747 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
748
749 mutex_lock(&applesmc_lock);
750
751 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
752 manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
753
754 mutex_unlock(&applesmc_lock);
755 if (ret)
756 return ret;
757 else
758 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
759}
760
761static ssize_t applesmc_store_fan_manual(struct device *dev,
762 struct device_attribute *devattr,
763 const char *sysfsbuf, size_t count)
764{
765 int ret;
766 u8 buffer[2];
767 u32 input;
768 u16 val;
769 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
770
771 input = simple_strtoul(sysfsbuf, NULL, 10);
772
773 mutex_lock(&applesmc_lock);
774
775 ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
776 val = (buffer[0] << 8 | buffer[1]);
777 if (ret)
778 goto out;
779
780 if (input)
781 val = val | (0x01 << attr->index);
782 else
783 val = val & ~(0x01 << attr->index);
784
785 buffer[0] = (val >> 8) & 0xFF;
786 buffer[1] = val & 0xFF;
787
788 ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
789
790out:
791 mutex_unlock(&applesmc_lock);
792 if (ret)
793 return ret;
794 else
795 return count;
796}
797
798static ssize_t applesmc_show_fan_position(struct device *dev,
799 struct device_attribute *attr, char *sysfsbuf)
800{
801 int ret;
802 char newkey[5];
803 u8 buffer[17];
804 struct sensor_device_attribute_2 *sensor_attr =
805 to_sensor_dev_attr_2(attr);
806
807 newkey[0] = FAN_POSITION[0];
808 newkey[1] = '0' + sensor_attr->index;
809 newkey[2] = FAN_POSITION[2];
810 newkey[3] = FAN_POSITION[3];
811 newkey[4] = 0;
812
813 mutex_lock(&applesmc_lock);
814
815 ret = applesmc_read_key(newkey, buffer, 16);
816 buffer[16] = 0;
817
818 mutex_unlock(&applesmc_lock);
819 if (ret)
820 return ret;
821 else
822 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
823}
824
825static ssize_t applesmc_calibrate_show(struct device *dev,
826 struct device_attribute *attr, char *sysfsbuf)
827{
828 return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
829}
830
831static ssize_t applesmc_calibrate_store(struct device *dev,
832 struct device_attribute *attr, const char *sysfsbuf, size_t count)
833{
834 mutex_lock(&applesmc_lock);
835 applesmc_calibrate();
836 mutex_unlock(&applesmc_lock);
837
838 return count;
839}
840
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700841static void applesmc_backlight_set(struct work_struct *work)
842{
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700843 mutex_lock(&applesmc_lock);
Henrik Rydberga976f152009-09-21 17:04:50 -0700844 applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700845 mutex_unlock(&applesmc_lock);
846}
847static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
848
849static void applesmc_brightness_set(struct led_classdev *led_cdev,
850 enum led_brightness value)
851{
852 int ret;
853
Henrik Rydberga976f152009-09-21 17:04:50 -0700854 backlight_state[0] = value;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700855 ret = queue_work(applesmc_led_wq, &backlight_work);
856
857 if (debug && (!ret))
858 printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
859}
860
861static ssize_t applesmc_key_count_show(struct device *dev,
862 struct device_attribute *attr, char *sysfsbuf)
863{
864 int ret;
865 u8 buffer[4];
866 u32 count;
867
868 mutex_lock(&applesmc_lock);
869
870 ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
871 count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
872 ((u32)buffer[2]<<8) + buffer[3];
873
874 mutex_unlock(&applesmc_lock);
875 if (ret)
876 return ret;
877 else
878 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
879}
880
881static ssize_t applesmc_key_at_index_read_show(struct device *dev,
882 struct device_attribute *attr, char *sysfsbuf)
883{
884 char key[5];
885 char info[6];
886 int ret;
887
888 mutex_lock(&applesmc_lock);
889
890 ret = applesmc_get_key_at_index(key_at_index, key);
891
892 if (ret || !key[0]) {
893 mutex_unlock(&applesmc_lock);
894
895 return -EINVAL;
896 }
897
898 ret = applesmc_get_key_type(key, info);
899
900 if (ret) {
901 mutex_unlock(&applesmc_lock);
902
903 return ret;
904 }
905
906 /*
907 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
908 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
909 */
910 ret = applesmc_read_key(key, sysfsbuf, info[0]);
911
912 mutex_unlock(&applesmc_lock);
913
914 if (!ret) {
915 return info[0];
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -0400916 } else {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -0700917 return ret;
918 }
919}
920
921static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
922 struct device_attribute *attr, char *sysfsbuf)
923{
924 char key[5];
925 char info[6];
926 int ret;
927
928 mutex_lock(&applesmc_lock);
929
930 ret = applesmc_get_key_at_index(key_at_index, key);
931
932 if (ret || !key[0]) {
933 mutex_unlock(&applesmc_lock);
934
935 return -EINVAL;
936 }
937
938 ret = applesmc_get_key_type(key, info);
939
940 mutex_unlock(&applesmc_lock);
941
942 if (!ret)
943 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
944 else
945 return ret;
946}
947
948static ssize_t applesmc_key_at_index_type_show(struct device *dev,
949 struct device_attribute *attr, char *sysfsbuf)
950{
951 char key[5];
952 char info[6];
953 int ret;
954
955 mutex_lock(&applesmc_lock);
956
957 ret = applesmc_get_key_at_index(key_at_index, key);
958
959 if (ret || !key[0]) {
960 mutex_unlock(&applesmc_lock);
961
962 return -EINVAL;
963 }
964
965 ret = applesmc_get_key_type(key, info);
966
967 mutex_unlock(&applesmc_lock);
968
969 if (!ret)
970 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
971 else
972 return ret;
973}
974
975static ssize_t applesmc_key_at_index_name_show(struct device *dev,
976 struct device_attribute *attr, char *sysfsbuf)
977{
978 char key[5];
979 int ret;
980
981 mutex_lock(&applesmc_lock);
982
983 ret = applesmc_get_key_at_index(key_at_index, key);
984
985 mutex_unlock(&applesmc_lock);
986
987 if (!ret && key[0])
988 return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
989 else
990 return -EINVAL;
991}
992
993static ssize_t applesmc_key_at_index_show(struct device *dev,
994 struct device_attribute *attr, char *sysfsbuf)
995{
996 return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
997}
998
999static ssize_t applesmc_key_at_index_store(struct device *dev,
1000 struct device_attribute *attr, const char *sysfsbuf, size_t count)
1001{
1002 mutex_lock(&applesmc_lock);
1003
1004 key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
1005
1006 mutex_unlock(&applesmc_lock);
1007
1008 return count;
1009}
1010
1011static struct led_classdev applesmc_backlight = {
Richard Purdie6c152be2007-10-31 15:00:07 +01001012 .name = "smc::kbd_backlight",
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001013 .default_trigger = "nand-disk",
1014 .brightness_set = applesmc_brightness_set,
1015};
1016
Nicolas Boichatfa744192007-05-23 13:58:13 -07001017static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
1018
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001019static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
1020static DEVICE_ATTR(calibrate, 0644,
1021 applesmc_calibrate_show, applesmc_calibrate_store);
1022
1023static struct attribute *accelerometer_attributes[] = {
1024 &dev_attr_position.attr,
1025 &dev_attr_calibrate.attr,
1026 NULL
1027};
1028
1029static const struct attribute_group accelerometer_attributes_group =
1030 { .attrs = accelerometer_attributes };
1031
1032static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
1033
1034static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
1035static DEVICE_ATTR(key_at_index, 0644,
1036 applesmc_key_at_index_show, applesmc_key_at_index_store);
1037static DEVICE_ATTR(key_at_index_name, 0444,
1038 applesmc_key_at_index_name_show, NULL);
1039static DEVICE_ATTR(key_at_index_type, 0444,
1040 applesmc_key_at_index_type_show, NULL);
1041static DEVICE_ATTR(key_at_index_data_length, 0444,
1042 applesmc_key_at_index_data_length_show, NULL);
1043static DEVICE_ATTR(key_at_index_data, 0444,
1044 applesmc_key_at_index_read_show, NULL);
1045
1046static struct attribute *key_enumeration_attributes[] = {
1047 &dev_attr_key_count.attr,
1048 &dev_attr_key_at_index.attr,
1049 &dev_attr_key_at_index_name.attr,
1050 &dev_attr_key_at_index_type.attr,
1051 &dev_attr_key_at_index_data_length.attr,
1052 &dev_attr_key_at_index_data.attr,
1053 NULL
1054};
1055
1056static const struct attribute_group key_enumeration_group =
1057 { .attrs = key_enumeration_attributes };
1058
1059/*
1060 * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
1061 * - show actual speed
1062 * - show/store minimum speed
1063 * - show maximum speed
1064 * - show safe speed
1065 * - show/store target speed
1066 * - show/store manual mode
1067 */
1068#define sysfs_fan_speeds_offset(offset) \
1069static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
1070 applesmc_show_fan_speed, NULL, 0, offset-1); \
1071\
1072static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
1073 applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
1074\
1075static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
1076 applesmc_show_fan_speed, NULL, 2, offset-1); \
1077\
1078static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
1079 applesmc_show_fan_speed, NULL, 3, offset-1); \
1080\
1081static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
1082 applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
1083\
1084static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
1085 applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
1086\
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001087static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001088 applesmc_show_fan_position, NULL, offset-1); \
1089\
1090static struct attribute *fan##offset##_attributes[] = { \
1091 &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
1092 &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
1093 &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
1094 &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
1095 &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
1096 &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
Jean Delvareda4e8ca2007-05-08 20:27:05 -07001097 &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001098 NULL \
1099};
1100
1101/*
1102 * Create the needed functions for each fan using the macro defined above
René Rebe8de57702007-10-16 14:19:20 -07001103 * (4 fans are supported)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001104 */
1105sysfs_fan_speeds_offset(1);
1106sysfs_fan_speeds_offset(2);
René Rebe8de57702007-10-16 14:19:20 -07001107sysfs_fan_speeds_offset(3);
1108sysfs_fan_speeds_offset(4);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001109
1110static const struct attribute_group fan_attribute_groups[] = {
1111 { .attrs = fan1_attributes },
René Rebe8de57702007-10-16 14:19:20 -07001112 { .attrs = fan2_attributes },
1113 { .attrs = fan3_attributes },
1114 { .attrs = fan4_attributes },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001115};
1116
1117/*
1118 * Temperature sensors sysfs entries.
1119 */
Alex Murrayfa5575c2010-05-27 19:58:54 +02001120static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO,
1121 applesmc_show_sensor_label, NULL, 0);
1122static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO,
1123 applesmc_show_sensor_label, NULL, 1);
1124static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO,
1125 applesmc_show_sensor_label, NULL, 2);
1126static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO,
1127 applesmc_show_sensor_label, NULL, 3);
1128static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO,
1129 applesmc_show_sensor_label, NULL, 4);
1130static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO,
1131 applesmc_show_sensor_label, NULL, 5);
1132static SENSOR_DEVICE_ATTR(temp7_label, S_IRUGO,
1133 applesmc_show_sensor_label, NULL, 6);
1134static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO,
1135 applesmc_show_sensor_label, NULL, 7);
1136static SENSOR_DEVICE_ATTR(temp9_label, S_IRUGO,
1137 applesmc_show_sensor_label, NULL, 8);
1138static SENSOR_DEVICE_ATTR(temp10_label, S_IRUGO,
1139 applesmc_show_sensor_label, NULL, 9);
1140static SENSOR_DEVICE_ATTR(temp11_label, S_IRUGO,
1141 applesmc_show_sensor_label, NULL, 10);
1142static SENSOR_DEVICE_ATTR(temp12_label, S_IRUGO,
1143 applesmc_show_sensor_label, NULL, 11);
1144static SENSOR_DEVICE_ATTR(temp13_label, S_IRUGO,
1145 applesmc_show_sensor_label, NULL, 12);
1146static SENSOR_DEVICE_ATTR(temp14_label, S_IRUGO,
1147 applesmc_show_sensor_label, NULL, 13);
1148static SENSOR_DEVICE_ATTR(temp15_label, S_IRUGO,
1149 applesmc_show_sensor_label, NULL, 14);
1150static SENSOR_DEVICE_ATTR(temp16_label, S_IRUGO,
1151 applesmc_show_sensor_label, NULL, 15);
1152static SENSOR_DEVICE_ATTR(temp17_label, S_IRUGO,
1153 applesmc_show_sensor_label, NULL, 16);
1154static SENSOR_DEVICE_ATTR(temp18_label, S_IRUGO,
1155 applesmc_show_sensor_label, NULL, 17);
1156static SENSOR_DEVICE_ATTR(temp19_label, S_IRUGO,
1157 applesmc_show_sensor_label, NULL, 18);
1158static SENSOR_DEVICE_ATTR(temp20_label, S_IRUGO,
1159 applesmc_show_sensor_label, NULL, 19);
1160static SENSOR_DEVICE_ATTR(temp21_label, S_IRUGO,
1161 applesmc_show_sensor_label, NULL, 20);
1162static SENSOR_DEVICE_ATTR(temp22_label, S_IRUGO,
1163 applesmc_show_sensor_label, NULL, 21);
1164static SENSOR_DEVICE_ATTR(temp23_label, S_IRUGO,
1165 applesmc_show_sensor_label, NULL, 22);
1166static SENSOR_DEVICE_ATTR(temp24_label, S_IRUGO,
1167 applesmc_show_sensor_label, NULL, 23);
1168static SENSOR_DEVICE_ATTR(temp25_label, S_IRUGO,
1169 applesmc_show_sensor_label, NULL, 24);
1170static SENSOR_DEVICE_ATTR(temp26_label, S_IRUGO,
1171 applesmc_show_sensor_label, NULL, 25);
1172static SENSOR_DEVICE_ATTR(temp27_label, S_IRUGO,
1173 applesmc_show_sensor_label, NULL, 26);
1174static SENSOR_DEVICE_ATTR(temp28_label, S_IRUGO,
1175 applesmc_show_sensor_label, NULL, 27);
1176static SENSOR_DEVICE_ATTR(temp29_label, S_IRUGO,
1177 applesmc_show_sensor_label, NULL, 28);
1178static SENSOR_DEVICE_ATTR(temp30_label, S_IRUGO,
1179 applesmc_show_sensor_label, NULL, 29);
1180static SENSOR_DEVICE_ATTR(temp31_label, S_IRUGO,
1181 applesmc_show_sensor_label, NULL, 30);
1182static SENSOR_DEVICE_ATTR(temp32_label, S_IRUGO,
1183 applesmc_show_sensor_label, NULL, 31);
1184static SENSOR_DEVICE_ATTR(temp33_label, S_IRUGO,
1185 applesmc_show_sensor_label, NULL, 32);
1186static SENSOR_DEVICE_ATTR(temp34_label, S_IRUGO,
1187 applesmc_show_sensor_label, NULL, 33);
1188static SENSOR_DEVICE_ATTR(temp35_label, S_IRUGO,
1189 applesmc_show_sensor_label, NULL, 34);
1190static SENSOR_DEVICE_ATTR(temp36_label, S_IRUGO,
1191 applesmc_show_sensor_label, NULL, 35);
1192static SENSOR_DEVICE_ATTR(temp37_label, S_IRUGO,
1193 applesmc_show_sensor_label, NULL, 36);
1194static SENSOR_DEVICE_ATTR(temp38_label, S_IRUGO,
1195 applesmc_show_sensor_label, NULL, 37);
1196static SENSOR_DEVICE_ATTR(temp39_label, S_IRUGO,
1197 applesmc_show_sensor_label, NULL, 38);
1198static SENSOR_DEVICE_ATTR(temp40_label, S_IRUGO,
1199 applesmc_show_sensor_label, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001200static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
1201 applesmc_show_temperature, NULL, 0);
1202static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
1203 applesmc_show_temperature, NULL, 1);
1204static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
1205 applesmc_show_temperature, NULL, 2);
1206static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
1207 applesmc_show_temperature, NULL, 3);
1208static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
1209 applesmc_show_temperature, NULL, 4);
1210static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
1211 applesmc_show_temperature, NULL, 5);
1212static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
1213 applesmc_show_temperature, NULL, 6);
1214static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
1215 applesmc_show_temperature, NULL, 7);
1216static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
1217 applesmc_show_temperature, NULL, 8);
1218static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
1219 applesmc_show_temperature, NULL, 9);
1220static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
1221 applesmc_show_temperature, NULL, 10);
1222static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
1223 applesmc_show_temperature, NULL, 11);
René Rebe8de57702007-10-16 14:19:20 -07001224static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
1225 applesmc_show_temperature, NULL, 12);
1226static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
1227 applesmc_show_temperature, NULL, 13);
1228static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
1229 applesmc_show_temperature, NULL, 14);
1230static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
1231 applesmc_show_temperature, NULL, 15);
1232static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
1233 applesmc_show_temperature, NULL, 16);
1234static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
1235 applesmc_show_temperature, NULL, 17);
1236static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
1237 applesmc_show_temperature, NULL, 18);
1238static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
1239 applesmc_show_temperature, NULL, 19);
1240static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
1241 applesmc_show_temperature, NULL, 20);
1242static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
1243 applesmc_show_temperature, NULL, 21);
1244static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
1245 applesmc_show_temperature, NULL, 22);
1246static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
1247 applesmc_show_temperature, NULL, 23);
1248static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
1249 applesmc_show_temperature, NULL, 24);
1250static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
1251 applesmc_show_temperature, NULL, 25);
1252static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
1253 applesmc_show_temperature, NULL, 26);
1254static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
1255 applesmc_show_temperature, NULL, 27);
1256static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
1257 applesmc_show_temperature, NULL, 28);
1258static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
1259 applesmc_show_temperature, NULL, 29);
1260static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
1261 applesmc_show_temperature, NULL, 30);
1262static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
1263 applesmc_show_temperature, NULL, 31);
1264static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
1265 applesmc_show_temperature, NULL, 32);
1266static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
1267 applesmc_show_temperature, NULL, 33);
1268static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
1269 applesmc_show_temperature, NULL, 34);
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001270static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
1271 applesmc_show_temperature, NULL, 35);
1272static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
1273 applesmc_show_temperature, NULL, 36);
1274static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
1275 applesmc_show_temperature, NULL, 37);
1276static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
1277 applesmc_show_temperature, NULL, 38);
1278static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
1279 applesmc_show_temperature, NULL, 39);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001280
Alex Murrayfa5575c2010-05-27 19:58:54 +02001281static struct attribute *label_attributes[] = {
1282 &sensor_dev_attr_temp1_label.dev_attr.attr,
1283 &sensor_dev_attr_temp2_label.dev_attr.attr,
1284 &sensor_dev_attr_temp3_label.dev_attr.attr,
1285 &sensor_dev_attr_temp4_label.dev_attr.attr,
1286 &sensor_dev_attr_temp5_label.dev_attr.attr,
1287 &sensor_dev_attr_temp6_label.dev_attr.attr,
1288 &sensor_dev_attr_temp7_label.dev_attr.attr,
1289 &sensor_dev_attr_temp8_label.dev_attr.attr,
1290 &sensor_dev_attr_temp9_label.dev_attr.attr,
1291 &sensor_dev_attr_temp10_label.dev_attr.attr,
1292 &sensor_dev_attr_temp11_label.dev_attr.attr,
1293 &sensor_dev_attr_temp12_label.dev_attr.attr,
1294 &sensor_dev_attr_temp13_label.dev_attr.attr,
1295 &sensor_dev_attr_temp14_label.dev_attr.attr,
1296 &sensor_dev_attr_temp15_label.dev_attr.attr,
1297 &sensor_dev_attr_temp16_label.dev_attr.attr,
1298 &sensor_dev_attr_temp17_label.dev_attr.attr,
1299 &sensor_dev_attr_temp18_label.dev_attr.attr,
1300 &sensor_dev_attr_temp19_label.dev_attr.attr,
1301 &sensor_dev_attr_temp20_label.dev_attr.attr,
1302 &sensor_dev_attr_temp21_label.dev_attr.attr,
1303 &sensor_dev_attr_temp22_label.dev_attr.attr,
1304 &sensor_dev_attr_temp23_label.dev_attr.attr,
1305 &sensor_dev_attr_temp24_label.dev_attr.attr,
1306 &sensor_dev_attr_temp25_label.dev_attr.attr,
1307 &sensor_dev_attr_temp26_label.dev_attr.attr,
1308 &sensor_dev_attr_temp27_label.dev_attr.attr,
1309 &sensor_dev_attr_temp28_label.dev_attr.attr,
1310 &sensor_dev_attr_temp29_label.dev_attr.attr,
1311 &sensor_dev_attr_temp30_label.dev_attr.attr,
1312 &sensor_dev_attr_temp31_label.dev_attr.attr,
1313 &sensor_dev_attr_temp32_label.dev_attr.attr,
1314 &sensor_dev_attr_temp33_label.dev_attr.attr,
1315 &sensor_dev_attr_temp34_label.dev_attr.attr,
1316 &sensor_dev_attr_temp35_label.dev_attr.attr,
1317 &sensor_dev_attr_temp36_label.dev_attr.attr,
1318 &sensor_dev_attr_temp37_label.dev_attr.attr,
1319 &sensor_dev_attr_temp38_label.dev_attr.attr,
1320 &sensor_dev_attr_temp39_label.dev_attr.attr,
1321 &sensor_dev_attr_temp40_label.dev_attr.attr,
1322 NULL
1323};
1324
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001325static struct attribute *temperature_attributes[] = {
1326 &sensor_dev_attr_temp1_input.dev_attr.attr,
1327 &sensor_dev_attr_temp2_input.dev_attr.attr,
1328 &sensor_dev_attr_temp3_input.dev_attr.attr,
1329 &sensor_dev_attr_temp4_input.dev_attr.attr,
1330 &sensor_dev_attr_temp5_input.dev_attr.attr,
1331 &sensor_dev_attr_temp6_input.dev_attr.attr,
1332 &sensor_dev_attr_temp7_input.dev_attr.attr,
1333 &sensor_dev_attr_temp8_input.dev_attr.attr,
1334 &sensor_dev_attr_temp9_input.dev_attr.attr,
1335 &sensor_dev_attr_temp10_input.dev_attr.attr,
1336 &sensor_dev_attr_temp11_input.dev_attr.attr,
1337 &sensor_dev_attr_temp12_input.dev_attr.attr,
René Rebe8de57702007-10-16 14:19:20 -07001338 &sensor_dev_attr_temp13_input.dev_attr.attr,
1339 &sensor_dev_attr_temp14_input.dev_attr.attr,
1340 &sensor_dev_attr_temp15_input.dev_attr.attr,
1341 &sensor_dev_attr_temp16_input.dev_attr.attr,
1342 &sensor_dev_attr_temp17_input.dev_attr.attr,
1343 &sensor_dev_attr_temp18_input.dev_attr.attr,
1344 &sensor_dev_attr_temp19_input.dev_attr.attr,
1345 &sensor_dev_attr_temp20_input.dev_attr.attr,
1346 &sensor_dev_attr_temp21_input.dev_attr.attr,
1347 &sensor_dev_attr_temp22_input.dev_attr.attr,
1348 &sensor_dev_attr_temp23_input.dev_attr.attr,
1349 &sensor_dev_attr_temp24_input.dev_attr.attr,
1350 &sensor_dev_attr_temp25_input.dev_attr.attr,
1351 &sensor_dev_attr_temp26_input.dev_attr.attr,
1352 &sensor_dev_attr_temp27_input.dev_attr.attr,
1353 &sensor_dev_attr_temp28_input.dev_attr.attr,
1354 &sensor_dev_attr_temp29_input.dev_attr.attr,
1355 &sensor_dev_attr_temp30_input.dev_attr.attr,
1356 &sensor_dev_attr_temp31_input.dev_attr.attr,
1357 &sensor_dev_attr_temp32_input.dev_attr.attr,
1358 &sensor_dev_attr_temp33_input.dev_attr.attr,
1359 &sensor_dev_attr_temp34_input.dev_attr.attr,
1360 &sensor_dev_attr_temp35_input.dev_attr.attr,
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001361 &sensor_dev_attr_temp36_input.dev_attr.attr,
1362 &sensor_dev_attr_temp37_input.dev_attr.attr,
1363 &sensor_dev_attr_temp38_input.dev_attr.attr,
1364 &sensor_dev_attr_temp39_input.dev_attr.attr,
1365 &sensor_dev_attr_temp40_input.dev_attr.attr,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001366 NULL
1367};
1368
1369static const struct attribute_group temperature_attributes_group =
1370 { .attrs = temperature_attributes };
1371
Alex Murrayfa5575c2010-05-27 19:58:54 +02001372static const struct attribute_group label_attributes_group = {
1373 .attrs = label_attributes
1374};
1375
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001376/* Module stuff */
1377
1378/*
1379 * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
1380 */
Jeff Garzik18552562007-10-03 15:15:40 -04001381static int applesmc_dmi_match(const struct dmi_system_id *id)
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001382{
1383 int i = 0;
1384 struct dmi_match_data* dmi_data = id->driver_data;
Joe Perches1ee7c712010-11-09 15:15:03 +00001385 pr_info("%s detected:\n", id->ident);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001386 applesmc_accelerometer = dmi_data->accelerometer;
Joe Perches1ee7c712010-11-09 15:15:03 +00001387 pr_info(" - Model %s accelerometer\n",
1388 applesmc_accelerometer ? "with" : "without");
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001389 applesmc_light = dmi_data->light;
Joe Perches1ee7c712010-11-09 15:15:03 +00001390 pr_info(" - Model %s light sensors and backlight\n",
1391 applesmc_light ? "with" : "without");
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001392
1393 applesmc_temperature_set = dmi_data->temperature_set;
1394 while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
1395 i++;
Joe Perches1ee7c712010-11-09 15:15:03 +00001396 pr_info(" - Model with %d temperature sensors\n", i);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001397 return 1;
1398}
1399
1400/* Create accelerometer ressources */
1401static int applesmc_create_accelerometer(void)
1402{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001403 struct input_dev *idev;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001404 int ret;
1405
1406 ret = sysfs_create_group(&pdev->dev.kobj,
1407 &accelerometer_attributes_group);
1408 if (ret)
1409 goto out;
1410
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001411 applesmc_idev = input_allocate_polled_device();
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001412 if (!applesmc_idev) {
1413 ret = -ENOMEM;
1414 goto out_sysfs;
1415 }
1416
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001417 applesmc_idev->poll = applesmc_idev_poll;
1418 applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
1419
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001420 /* initial calibrate for the input device */
1421 applesmc_calibrate();
1422
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001423 /* initialize the input device */
1424 idev = applesmc_idev->input;
1425 idev->name = "applesmc";
1426 idev->id.bustype = BUS_HOST;
1427 idev->dev.parent = &pdev->dev;
Jiri Slaby7b19ada2007-10-18 23:40:32 -07001428 idev->evbit[0] = BIT_MASK(EV_ABS);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001429 input_set_abs_params(idev, ABS_X,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001430 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001431 input_set_abs_params(idev, ABS_Y,
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001432 -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
1433
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001434 ret = input_register_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001435 if (ret)
1436 goto out_idev;
1437
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001438 return 0;
1439
1440out_idev:
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001441 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001442
1443out_sysfs:
1444 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1445
1446out:
Joe Perches1ee7c712010-11-09 15:15:03 +00001447 pr_warn("driver init failed (ret=%d)!\n", ret);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001448 return ret;
1449}
1450
1451/* Release all ressources used by the accelerometer */
1452static void applesmc_release_accelerometer(void)
1453{
Dmitry Torokhovd5cf2b92007-09-26 00:01:35 -04001454 input_unregister_polled_device(applesmc_idev);
1455 input_free_polled_device(applesmc_idev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001456 sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
1457}
1458
1459static __initdata struct dmi_match_data applesmc_dmi_data[] = {
1460/* MacBook Pro: accelerometer, backlight and temperature set 0 */
1461 { .accelerometer = 1, .light = 1, .temperature_set = 0 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001462/* MacBook2: accelerometer and temperature set 1 */
Martin Szulecki1bed24b2007-07-09 11:41:36 -07001463 { .accelerometer = 1, .light = 0, .temperature_set = 1 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001464/* MacBook: accelerometer and temperature set 2 */
1465 { .accelerometer = 1, .light = 0, .temperature_set = 2 },
1466/* MacMini: temperature set 3 */
René Rebe8de57702007-10-16 14:19:20 -07001467 { .accelerometer = 0, .light = 0, .temperature_set = 3 },
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001468/* MacPro: temperature set 4 */
1469 { .accelerometer = 0, .light = 0, .temperature_set = 4 },
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001470/* iMac: temperature set 5 */
1471 { .accelerometer = 0, .light = 0, .temperature_set = 5 },
Henrik Rydberg468cc032008-11-12 13:24:58 -08001472/* MacBook3, MacBook4: accelerometer and temperature set 6 */
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001473 { .accelerometer = 1, .light = 0, .temperature_set = 6 },
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001474/* MacBook Air: accelerometer, backlight and temperature set 7 */
1475 { .accelerometer = 1, .light = 1, .temperature_set = 7 },
Henrik Rydbergd7549902008-10-18 20:27:41 -07001476/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
1477 { .accelerometer = 1, .light = 1, .temperature_set = 8 },
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001478/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
1479 { .accelerometer = 1, .light = 1, .temperature_set = 9 },
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001480/* iMac 5: light sensor only, temperature set 10 */
1481 { .accelerometer = 0, .light = 0, .temperature_set = 10 },
Henrik Rydberg181209a2008-11-06 12:53:20 -08001482/* MacBook 5: accelerometer, backlight and temperature set 11 */
1483 { .accelerometer = 1, .light = 1, .temperature_set = 11 },
Henrik Rydberga6660322008-11-06 12:53:21 -08001484/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
1485 { .accelerometer = 1, .light = 1, .temperature_set = 12 },
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001486/* iMac 8: light sensor only, temperature set 13 */
1487 { .accelerometer = 0, .light = 0, .temperature_set = 13 },
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001488/* iMac 6: light sensor only, temperature set 14 */
1489 { .accelerometer = 0, .light = 0, .temperature_set = 14 },
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001490/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
1491 { .accelerometer = 1, .light = 1, .temperature_set = 15 },
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001492/* MacPro3,1: temperature set 16 */
1493 { .accelerometer = 0, .light = 0, .temperature_set = 16 },
Justin P. Mattocke1741712010-04-14 16:14:10 +02001494/* iMac 9,1: light sensor only, temperature set 17 */
1495 { .accelerometer = 0, .light = 0, .temperature_set = 17 },
1496/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
1497 { .accelerometer = 1, .light = 1, .temperature_set = 18 },
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +02001498/* MacBook Pro 5,3: accelerometer, backlight and temperature set 19 */
1499 { .accelerometer = 1, .light = 1, .temperature_set = 19 },
1500/* MacBook Pro 5,4: accelerometer, backlight and temperature set 20 */
1501 { .accelerometer = 1, .light = 1, .temperature_set = 20 },
Bernhard Froemel872bad52010-05-27 19:58:52 +02001502/* MacBook Pro 6,2: accelerometer, backlight and temperature set 21 */
1503 { .accelerometer = 1, .light = 1, .temperature_set = 21 },
Henrik Rydberg405eaa12010-05-27 19:58:53 +02001504/* MacBook Pro 7,1: accelerometer, backlight and temperature set 22 */
1505 { .accelerometer = 1, .light = 1, .temperature_set = 22 },
Edgar Hucek132af032010-11-09 15:15:01 +00001506/* MacBook Air 3,1: accelerometer, backlight and temperature set 23 */
1507 { .accelerometer = 0, .light = 0, .temperature_set = 23 },
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001508};
1509
1510/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
1511 * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
1512static __initdata struct dmi_system_id applesmc_whitelist[] = {
Edgar Hucek132af032010-11-09 15:15:01 +00001513 { applesmc_dmi_match, "Apple MacBook Air 3", {
1514 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1515 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3") },
1516 &applesmc_dmi_data[23]},
Henrik Rydberg85e0e5a2009-01-06 14:41:36 -08001517 { applesmc_dmi_match, "Apple MacBook Air 2", {
1518 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1519 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
1520 &applesmc_dmi_data[15]},
Henrik Rydbergf5274c92008-10-18 20:27:40 -07001521 { applesmc_dmi_match, "Apple MacBook Air", {
1522 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1523 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001524 &applesmc_dmi_data[7]},
Henrik Rydberg405eaa12010-05-27 19:58:53 +02001525 { applesmc_dmi_match, "Apple MacBook Pro 7", {
1526 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1527 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro7") },
1528 &applesmc_dmi_data[22]},
Henrik Rydberg4e4a99d2010-05-27 19:58:50 +02001529 { applesmc_dmi_match, "Apple MacBook Pro 5,4", {
1530 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1531 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4") },
1532 &applesmc_dmi_data[20]},
1533 { applesmc_dmi_match, "Apple MacBook Pro 5,3", {
1534 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1535 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3") },
1536 &applesmc_dmi_data[19]},
Bernhard Froemel872bad52010-05-27 19:58:52 +02001537 { applesmc_dmi_match, "Apple MacBook Pro 6", {
1538 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1539 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6") },
1540 &applesmc_dmi_data[21]},
Henrik Rydberga6660322008-11-06 12:53:21 -08001541 { applesmc_dmi_match, "Apple MacBook Pro 5", {
1542 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1543 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
1544 &applesmc_dmi_data[12]},
Henrik Rydbergd7549902008-10-18 20:27:41 -07001545 { applesmc_dmi_match, "Apple MacBook Pro 4", {
1546 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1547 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
1548 &applesmc_dmi_data[8]},
Henrik Rydberg07e8dbd2008-10-18 20:27:42 -07001549 { applesmc_dmi_match, "Apple MacBook Pro 3", {
1550 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1551 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
1552 &applesmc_dmi_data[9]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001553 { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
1554 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
1555 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
1556 &applesmc_dmi_data[18]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001557 { applesmc_dmi_match, "Apple MacBook Pro", {
1558 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1559 DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001560 &applesmc_dmi_data[0]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001561 { applesmc_dmi_match, "Apple MacBook (v2)", {
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001562 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001563 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001564 &applesmc_dmi_data[1]},
Guilherme M. Schroederf91a79f2008-08-15 00:40:32 -07001565 { applesmc_dmi_match, "Apple MacBook (v3)", {
1566 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1567 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001568 &applesmc_dmi_data[6]},
Henrik Rydberg468cc032008-11-12 13:24:58 -08001569 { applesmc_dmi_match, "Apple MacBook 4", {
1570 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1571 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
1572 &applesmc_dmi_data[6]},
Henrik Rydberg181209a2008-11-06 12:53:20 -08001573 { applesmc_dmi_match, "Apple MacBook 5", {
1574 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1575 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
1576 &applesmc_dmi_data[11]},
Riki Oktariantocd19ba12008-02-04 23:41:58 -08001577 { applesmc_dmi_match, "Apple MacBook", {
1578 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1579 DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001580 &applesmc_dmi_data[2]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001581 { applesmc_dmi_match, "Apple Macmini", {
1582 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1583 DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001584 &applesmc_dmi_data[3]},
René Rebe8de57702007-10-16 14:19:20 -07001585 { applesmc_dmi_match, "Apple MacPro2", {
1586 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1587 DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001588 &applesmc_dmi_data[4]},
Bharath Rameshfb9f88e2009-01-29 14:25:24 -08001589 { applesmc_dmi_match, "Apple MacPro3", {
1590 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1591 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
1592 &applesmc_dmi_data[16]},
Henrik Rydberg45a3a362008-11-19 15:36:42 -08001593 { applesmc_dmi_match, "Apple MacPro", {
1594 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1595 DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
1596 &applesmc_dmi_data[4]},
Justin P. Mattocke1741712010-04-14 16:14:10 +02001597 { applesmc_dmi_match, "Apple iMac 9,1", {
1598 DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
1599 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
1600 &applesmc_dmi_data[17]},
Henrik Rydbergeefc4882008-11-06 12:53:22 -08001601 { applesmc_dmi_match, "Apple iMac 8", {
1602 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1603 DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
1604 &applesmc_dmi_data[13]},
Henrik Rydberg9ca791b2008-11-19 15:36:06 -08001605 { applesmc_dmi_match, "Apple iMac 6", {
1606 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1607 DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
1608 &applesmc_dmi_data[14]},
Henrik Rydberg6e3530f2008-11-06 12:53:19 -08001609 { applesmc_dmi_match, "Apple iMac 5", {
1610 DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
1611 DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
1612 &applesmc_dmi_data[10]},
Roberto De Ioris9f86f282008-08-15 00:40:30 -07001613 { applesmc_dmi_match, "Apple iMac", {
1614 DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
1615 DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
Andrew Morton7b5e3cb2008-10-18 20:27:41 -07001616 &applesmc_dmi_data[5]},
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001617 { .ident = NULL }
1618};
1619
1620static int __init applesmc_init(void)
1621{
1622 int ret;
1623 int count;
1624 int i;
1625
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001626 if (!dmi_check_system(applesmc_whitelist)) {
Joe Perches1ee7c712010-11-09 15:15:03 +00001627 pr_warn("supported laptop not found!\n");
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001628 ret = -ENODEV;
1629 goto out;
1630 }
1631
1632 if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
1633 "applesmc")) {
1634 ret = -ENXIO;
1635 goto out;
1636 }
1637
1638 ret = platform_driver_register(&applesmc_driver);
1639 if (ret)
1640 goto out_region;
1641
Jean Delvareddfbf2a2007-05-08 20:27:04 -07001642 pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
1643 NULL, 0);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001644 if (IS_ERR(pdev)) {
1645 ret = PTR_ERR(pdev);
1646 goto out_driver;
1647 }
1648
Nicolas Boichatfa744192007-05-23 13:58:13 -07001649 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001650 if (ret)
1651 goto out_device;
Nicolas Boichatfa744192007-05-23 13:58:13 -07001652
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001653 /* Create key enumeration sysfs files */
1654 ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
1655 if (ret)
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001656 goto out_name;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001657
1658 /* create fan files */
1659 count = applesmc_get_fan_count();
Henrik Rydberg0559a532010-05-11 09:17:47 +02001660 if (count < 0)
Joe Perches1ee7c712010-11-09 15:15:03 +00001661 pr_err("Cannot get the number of fans\n");
Henrik Rydberg0559a532010-05-11 09:17:47 +02001662 else
Joe Perches1ee7c712010-11-09 15:15:03 +00001663 pr_info("%d fans found\n", count);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001664
Henrik Rydberg0559a532010-05-11 09:17:47 +02001665 if (count > 4) {
1666 count = 4;
Joe Perches1ee7c712010-11-09 15:15:03 +00001667 pr_warn("A maximum of 4 fans are supported by this driver\n");
Henrik Rydberg0559a532010-05-11 09:17:47 +02001668 }
1669
1670 while (fans_handled < count) {
1671 ret = sysfs_create_group(&pdev->dev.kobj,
1672 &fan_attribute_groups[fans_handled]);
1673 if (ret)
1674 goto out_fans;
1675 fans_handled++;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001676 }
1677
1678 for (i = 0;
1679 temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
1680 i++) {
Alex Murrayfa5575c2010-05-27 19:58:54 +02001681 if (temperature_attributes[i] == NULL ||
1682 label_attributes[i] == NULL) {
Joe Perches1ee7c712010-11-09 15:15:03 +00001683 pr_err("More temperature sensors in temperature_sensors_sets (at least %i) than available sysfs files in temperature_attributes (%i), please report this bug\n",
1684 i, i-1);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001685 goto out_temperature;
1686 }
1687 ret = sysfs_create_file(&pdev->dev.kobj,
1688 temperature_attributes[i]);
1689 if (ret)
1690 goto out_temperature;
Alex Murrayfa5575c2010-05-27 19:58:54 +02001691 ret = sysfs_create_file(&pdev->dev.kobj,
1692 label_attributes[i]);
1693 if (ret)
1694 goto out_temperature;
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001695 }
1696
1697 if (applesmc_accelerometer) {
1698 ret = applesmc_create_accelerometer();
1699 if (ret)
1700 goto out_temperature;
1701 }
1702
1703 if (applesmc_light) {
1704 /* Add light sensor file */
1705 ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
1706 if (ret)
1707 goto out_accelerometer;
1708
1709 /* Create the workqueue */
1710 applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
1711 if (!applesmc_led_wq) {
1712 ret = -ENOMEM;
1713 goto out_light_sysfs;
1714 }
1715
1716 /* register as a led device */
1717 ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
1718 if (ret < 0)
1719 goto out_light_wq;
1720 }
1721
Tony Jones1beeffe2007-08-20 13:46:20 -07001722 hwmon_dev = hwmon_device_register(&pdev->dev);
1723 if (IS_ERR(hwmon_dev)) {
1724 ret = PTR_ERR(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001725 goto out_light_ledclass;
1726 }
1727
Joe Perches1ee7c712010-11-09 15:15:03 +00001728 pr_info("driver successfully loaded\n");
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001729
1730 return 0;
1731
1732out_light_ledclass:
1733 if (applesmc_light)
1734 led_classdev_unregister(&applesmc_backlight);
1735out_light_wq:
1736 if (applesmc_light)
1737 destroy_workqueue(applesmc_led_wq);
1738out_light_sysfs:
1739 if (applesmc_light)
1740 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1741out_accelerometer:
1742 if (applesmc_accelerometer)
1743 applesmc_release_accelerometer();
1744out_temperature:
Alex Murrayfa5575c2010-05-27 19:58:54 +02001745 sysfs_remove_group(&pdev->dev.kobj, &label_attributes_group);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001746 sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
Henrik Rydberg0559a532010-05-11 09:17:47 +02001747out_fans:
1748 while (fans_handled)
1749 sysfs_remove_group(&pdev->dev.kobj,
1750 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001751 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001752out_name:
1753 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001754out_device:
1755 platform_device_unregister(pdev);
1756out_driver:
1757 platform_driver_unregister(&applesmc_driver);
1758out_region:
1759 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1760out:
Joe Perches1ee7c712010-11-09 15:15:03 +00001761 pr_warn("driver init failed (ret=%d)!\n", ret);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001762 return ret;
1763}
1764
1765static void __exit applesmc_exit(void)
1766{
Tony Jones1beeffe2007-08-20 13:46:20 -07001767 hwmon_device_unregister(hwmon_dev);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001768 if (applesmc_light) {
1769 led_classdev_unregister(&applesmc_backlight);
1770 destroy_workqueue(applesmc_led_wq);
1771 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
1772 }
1773 if (applesmc_accelerometer)
1774 applesmc_release_accelerometer();
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 +02001777 while (fans_handled)
1778 sysfs_remove_group(&pdev->dev.kobj,
1779 &fan_attribute_groups[--fans_handled]);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001780 sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
Nicolas Boichat6996abf2007-05-27 22:17:43 +02001781 sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001782 platform_device_unregister(pdev);
1783 platform_driver_unregister(&applesmc_driver);
1784 release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
1785
Joe Perches1ee7c712010-11-09 15:15:03 +00001786 pr_info("driver unloaded\n");
Nicolas Boichat6f2fad72007-05-08 00:24:52 -07001787}
1788
1789module_init(applesmc_init);
1790module_exit(applesmc_exit);
1791
1792MODULE_AUTHOR("Nicolas Boichat");
1793MODULE_DESCRIPTION("Apple SMC");
1794MODULE_LICENSE("GPL v2");
Henrik Rydbergdc924ef2008-12-01 13:13:49 -08001795MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);