Commit bd5f47ec961594b1091839333600008f8166fd00

Authored by Jean Delvare
Committed by Jean Delvare
1 parent 6dfee85397

Move ams driver to macintosh

The ams driver isn't a hardware monitoring driver, so it shouldn't
live under driver/hwmon. drivers/macintosh seems much more
appropriate, as the driver is only useful on PowerBooks and iBooks.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Guenter Roeck <guenter.roeck@ericsson.com>
Cc: Stelian Pop <stelian@popies.net>
Cc: Michael Hanselmann <linux-kernel@hansmi.ch>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Grant Likely <grant.likely@secretlab.ca>

Showing 17 changed files with 992 additions and 991 deletions Side-by-side Diff

... ... @@ -432,7 +432,7 @@
432 432 M: Stelian Pop <stelian@popies.net>
433 433 M: Michael Hanselmann <linux-kernel@hansmi.ch>
434 434 S: Supported
435   -F: drivers/hwmon/ams/
  435 +F: drivers/macintosh/ams/
436 436  
437 437 AMSO1100 RNIC DRIVER
438 438 M: Tom Tucker <tom@opengridcomputing.com>
drivers/hwmon/Kconfig
... ... @@ -249,32 +249,6 @@
249 249 This driver can also be built as a module. If so, the module
250 250 will be called k10temp.
251 251  
252   -config SENSORS_AMS
253   - tristate "Apple Motion Sensor driver"
254   - depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
255   - select INPUT_POLLDEV
256   - help
257   - Support for the motion sensor included in PowerBooks. Includes
258   - implementations for PMU and I2C.
259   -
260   - This driver can also be built as a module. If so, the module
261   - will be called ams.
262   -
263   -config SENSORS_AMS_PMU
264   - bool "PMU variant"
265   - depends on SENSORS_AMS && ADB_PMU
266   - default y
267   - help
268   - PMU variant of motion sensor, found in late 2005 PowerBooks.
269   -
270   -config SENSORS_AMS_I2C
271   - bool "I2C variant"
272   - depends on SENSORS_AMS && I2C
273   - default y
274   - help
275   - I2C variant of motion sensor, found in early 2005 PowerBooks and
276   - iBooks.
277   -
278 252 config SENSORS_ASB100
279 253 tristate "Asus ASB100 Bach"
280 254 depends on X86 && I2C && EXPERIMENTAL
drivers/hwmon/Makefile
... ... @@ -36,7 +36,6 @@
36 36 obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
37 37 obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
38 38 obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
39   -obj-$(CONFIG_SENSORS_AMS) += ams/
40 39 obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
41 40 obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
42 41 obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
drivers/hwmon/ams/Makefile
1   -#
2   -# Makefile for Apple Motion Sensor driver
3   -#
4   -
5   -ams-y := ams-core.o ams-input.o
6   -ams-$(CONFIG_SENSORS_AMS_PMU) += ams-pmu.o
7   -ams-$(CONFIG_SENSORS_AMS_I2C) += ams-i2c.o
8   -obj-$(CONFIG_SENSORS_AMS) += ams.o
drivers/hwmon/ams/ams-core.c
1   -/*
2   - * Apple Motion Sensor driver
3   - *
4   - * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
5   - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
6   - *
7   - * This program is free software; you can redistribute it and/or modify
8   - * it under the terms of the GNU General Public License as published by
9   - * the Free Software Foundation; either version 2 of the License, or
10   - * (at your option) any later version.
11   - *
12   - * This program is distributed in the hope that it will be useful,
13   - * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15   - * GNU General Public License for more details.
16   - *
17   - * You should have received a copy of the GNU General Public License
18   - * along with this program; if not, write to the Free Software
19   - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20   - */
21   -
22   -#include <linux/module.h>
23   -#include <linux/types.h>
24   -#include <linux/errno.h>
25   -#include <linux/init.h>
26   -#include <linux/of_platform.h>
27   -#include <asm/pmac_pfunc.h>
28   -
29   -#include "ams.h"
30   -
31   -/* There is only one motion sensor per machine */
32   -struct ams ams_info;
33   -
34   -static unsigned int verbose;
35   -module_param(verbose, bool, 0644);
36   -MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
37   -
38   -/* Call with ams_info.lock held! */
39   -void ams_sensors(s8 *x, s8 *y, s8 *z)
40   -{
41   - u32 orient = ams_info.vflag? ams_info.orient1 : ams_info.orient2;
42   -
43   - if (orient & 0x80)
44   - /* X and Y swapped */
45   - ams_info.get_xyz(y, x, z);
46   - else
47   - ams_info.get_xyz(x, y, z);
48   -
49   - if (orient & 0x04)
50   - *z = ~(*z);
51   - if (orient & 0x02)
52   - *y = ~(*y);
53   - if (orient & 0x01)
54   - *x = ~(*x);
55   -}
56   -
57   -static ssize_t ams_show_current(struct device *dev,
58   - struct device_attribute *attr, char *buf)
59   -{
60   - s8 x, y, z;
61   -
62   - mutex_lock(&ams_info.lock);
63   - ams_sensors(&x, &y, &z);
64   - mutex_unlock(&ams_info.lock);
65   -
66   - return snprintf(buf, PAGE_SIZE, "%d %d %d\n", x, y, z);
67   -}
68   -
69   -static DEVICE_ATTR(current, S_IRUGO, ams_show_current, NULL);
70   -
71   -static void ams_handle_irq(void *data)
72   -{
73   - enum ams_irq irq = *((enum ams_irq *)data);
74   -
75   - spin_lock(&ams_info.irq_lock);
76   -
77   - ams_info.worker_irqs |= irq;
78   - schedule_work(&ams_info.worker);
79   -
80   - spin_unlock(&ams_info.irq_lock);
81   -}
82   -
83   -static enum ams_irq ams_freefall_irq_data = AMS_IRQ_FREEFALL;
84   -static struct pmf_irq_client ams_freefall_client = {
85   - .owner = THIS_MODULE,
86   - .handler = ams_handle_irq,
87   - .data = &ams_freefall_irq_data,
88   -};
89   -
90   -static enum ams_irq ams_shock_irq_data = AMS_IRQ_SHOCK;
91   -static struct pmf_irq_client ams_shock_client = {
92   - .owner = THIS_MODULE,
93   - .handler = ams_handle_irq,
94   - .data = &ams_shock_irq_data,
95   -};
96   -
97   -/* Once hard disk parking is implemented in the kernel, this function can
98   - * trigger it.
99   - */
100   -static void ams_worker(struct work_struct *work)
101   -{
102   - unsigned long flags;
103   - u8 irqs_to_clear;
104   -
105   - mutex_lock(&ams_info.lock);
106   -
107   - spin_lock_irqsave(&ams_info.irq_lock, flags);
108   - irqs_to_clear = ams_info.worker_irqs;
109   -
110   - if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) {
111   - if (verbose)
112   - printk(KERN_INFO "ams: freefall detected!\n");
113   -
114   - ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL;
115   - }
116   -
117   - if (ams_info.worker_irqs & AMS_IRQ_SHOCK) {
118   - if (verbose)
119   - printk(KERN_INFO "ams: shock detected!\n");
120   -
121   - ams_info.worker_irqs &= ~AMS_IRQ_SHOCK;
122   - }
123   -
124   - spin_unlock_irqrestore(&ams_info.irq_lock, flags);
125   -
126   - ams_info.clear_irq(irqs_to_clear);
127   -
128   - mutex_unlock(&ams_info.lock);
129   -}
130   -
131   -/* Call with ams_info.lock held! */
132   -int ams_sensor_attach(void)
133   -{
134   - int result;
135   - const u32 *prop;
136   -
137   - /* Get orientation */
138   - prop = of_get_property(ams_info.of_node, "orientation", NULL);
139   - if (!prop)
140   - return -ENODEV;
141   - ams_info.orient1 = *prop;
142   - ams_info.orient2 = *(prop + 1);
143   -
144   - /* Register freefall interrupt handler */
145   - result = pmf_register_irq_client(ams_info.of_node,
146   - "accel-int-1",
147   - &ams_freefall_client);
148   - if (result < 0)
149   - return -ENODEV;
150   -
151   - /* Reset saved irqs */
152   - ams_info.worker_irqs = 0;
153   -
154   - /* Register shock interrupt handler */
155   - result = pmf_register_irq_client(ams_info.of_node,
156   - "accel-int-2",
157   - &ams_shock_client);
158   - if (result < 0)
159   - goto release_freefall;
160   -
161   - /* Create device */
162   - ams_info.of_dev = of_platform_device_create(ams_info.of_node, "ams", NULL);
163   - if (!ams_info.of_dev) {
164   - result = -ENODEV;
165   - goto release_shock;
166   - }
167   -
168   - /* Create attributes */
169   - result = device_create_file(&ams_info.of_dev->dev, &dev_attr_current);
170   - if (result)
171   - goto release_of;
172   -
173   - ams_info.vflag = !!(ams_info.get_vendor() & 0x10);
174   -
175   - /* Init input device */
176   - result = ams_input_init();
177   - if (result)
178   - goto release_device_file;
179   -
180   - return result;
181   -release_device_file:
182   - device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
183   -release_of:
184   - of_device_unregister(ams_info.of_dev);
185   -release_shock:
186   - pmf_unregister_irq_client(&ams_shock_client);
187   -release_freefall:
188   - pmf_unregister_irq_client(&ams_freefall_client);
189   - return result;
190   -}
191   -
192   -int __init ams_init(void)
193   -{
194   - struct device_node *np;
195   -
196   - spin_lock_init(&ams_info.irq_lock);
197   - mutex_init(&ams_info.lock);
198   - INIT_WORK(&ams_info.worker, ams_worker);
199   -
200   -#ifdef CONFIG_SENSORS_AMS_I2C
201   - np = of_find_node_by_name(NULL, "accelerometer");
202   - if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
203   - /* Found I2C motion sensor */
204   - return ams_i2c_init(np);
205   -#endif
206   -
207   -#ifdef CONFIG_SENSORS_AMS_PMU
208   - np = of_find_node_by_name(NULL, "sms");
209   - if (np && of_device_is_compatible(np, "sms"))
210   - /* Found PMU motion sensor */
211   - return ams_pmu_init(np);
212   -#endif
213   - return -ENODEV;
214   -}
215   -
216   -void ams_sensor_detach(void)
217   -{
218   - /* Remove input device */
219   - ams_input_exit();
220   -
221   - /* Remove attributes */
222   - device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
223   -
224   - /* Flush interrupt worker
225   - *
226   - * We do this after ams_info.exit(), because an interrupt might
227   - * have arrived before disabling them.
228   - */
229   - flush_scheduled_work();
230   -
231   - /* Remove device */
232   - of_device_unregister(ams_info.of_dev);
233   -
234   - /* Remove handler */
235   - pmf_unregister_irq_client(&ams_shock_client);
236   - pmf_unregister_irq_client(&ams_freefall_client);
237   -}
238   -
239   -static void __exit ams_exit(void)
240   -{
241   - /* Shut down implementation */
242   - ams_info.exit();
243   -}
244   -
245   -MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
246   -MODULE_DESCRIPTION("Apple Motion Sensor driver");
247   -MODULE_LICENSE("GPL");
248   -
249   -module_init(ams_init);
250   -module_exit(ams_exit);
drivers/hwmon/ams/ams-i2c.c
1   -/*
2   - * Apple Motion Sensor driver (I2C variant)
3   - *
4   - * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
5   - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
6   - *
7   - * Clean room implementation based on the reverse engineered Mac OS X driver by
8   - * Johannes Berg <johannes@sipsolutions.net>, documentation available at
9   - * http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification
10   - *
11   - * This program is free software; you can redistribute it and/or modify
12   - * it under the terms of the GNU General Public License as published by
13   - * the Free Software Foundation; either version 2 of the License, or
14   - * (at your option) any later version.
15   - */
16   -
17   -#include <linux/module.h>
18   -#include <linux/types.h>
19   -#include <linux/errno.h>
20   -#include <linux/init.h>
21   -#include <linux/delay.h>
22   -
23   -#include "ams.h"
24   -
25   -/* AMS registers */
26   -#define AMS_COMMAND 0x00 /* command register */
27   -#define AMS_STATUS 0x01 /* status register */
28   -#define AMS_CTRL1 0x02 /* read control 1 (number of values) */
29   -#define AMS_CTRL2 0x03 /* read control 2 (offset?) */
30   -#define AMS_CTRL3 0x04 /* read control 3 (size of each value?) */
31   -#define AMS_DATA1 0x05 /* read data 1 */
32   -#define AMS_DATA2 0x06 /* read data 2 */
33   -#define AMS_DATA3 0x07 /* read data 3 */
34   -#define AMS_DATA4 0x08 /* read data 4 */
35   -#define AMS_DATAX 0x20 /* data X */
36   -#define AMS_DATAY 0x21 /* data Y */
37   -#define AMS_DATAZ 0x22 /* data Z */
38   -#define AMS_FREEFALL 0x24 /* freefall int control */
39   -#define AMS_SHOCK 0x25 /* shock int control */
40   -#define AMS_SENSLOW 0x26 /* sensitivity low limit */
41   -#define AMS_SENSHIGH 0x27 /* sensitivity high limit */
42   -#define AMS_CTRLX 0x28 /* control X */
43   -#define AMS_CTRLY 0x29 /* control Y */
44   -#define AMS_CTRLZ 0x2A /* control Z */
45   -#define AMS_UNKNOWN1 0x2B /* unknown 1 */
46   -#define AMS_UNKNOWN2 0x2C /* unknown 2 */
47   -#define AMS_UNKNOWN3 0x2D /* unknown 3 */
48   -#define AMS_VENDOR 0x2E /* vendor */
49   -
50   -/* AMS commands - use with the AMS_COMMAND register */
51   -enum ams_i2c_cmd {
52   - AMS_CMD_NOOP = 0,
53   - AMS_CMD_VERSION,
54   - AMS_CMD_READMEM,
55   - AMS_CMD_WRITEMEM,
56   - AMS_CMD_ERASEMEM,
57   - AMS_CMD_READEE,
58   - AMS_CMD_WRITEEE,
59   - AMS_CMD_RESET,
60   - AMS_CMD_START,
61   -};
62   -
63   -static int ams_i2c_probe(struct i2c_client *client,
64   - const struct i2c_device_id *id);
65   -static int ams_i2c_remove(struct i2c_client *client);
66   -
67   -static const struct i2c_device_id ams_id[] = {
68   - { "ams", 0 },
69   - { }
70   -};
71   -MODULE_DEVICE_TABLE(i2c, ams_id);
72   -
73   -static struct i2c_driver ams_i2c_driver = {
74   - .driver = {
75   - .name = "ams",
76   - .owner = THIS_MODULE,
77   - },
78   - .probe = ams_i2c_probe,
79   - .remove = ams_i2c_remove,
80   - .id_table = ams_id,
81   -};
82   -
83   -static s32 ams_i2c_read(u8 reg)
84   -{
85   - return i2c_smbus_read_byte_data(ams_info.i2c_client, reg);
86   -}
87   -
88   -static int ams_i2c_write(u8 reg, u8 value)
89   -{
90   - return i2c_smbus_write_byte_data(ams_info.i2c_client, reg, value);
91   -}
92   -
93   -static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
94   -{
95   - s32 result;
96   - int count = 3;
97   -
98   - ams_i2c_write(AMS_COMMAND, cmd);
99   - msleep(5);
100   -
101   - while (count--) {
102   - result = ams_i2c_read(AMS_COMMAND);
103   - if (result == 0 || result & 0x80)
104   - return 0;
105   -
106   - schedule_timeout_uninterruptible(HZ / 20);
107   - }
108   -
109   - return -1;
110   -}
111   -
112   -static void ams_i2c_set_irq(enum ams_irq reg, char enable)
113   -{
114   - if (reg & AMS_IRQ_FREEFALL) {
115   - u8 val = ams_i2c_read(AMS_CTRLX);
116   - if (enable)
117   - val |= 0x80;
118   - else
119   - val &= ~0x80;
120   - ams_i2c_write(AMS_CTRLX, val);
121   - }
122   -
123   - if (reg & AMS_IRQ_SHOCK) {
124   - u8 val = ams_i2c_read(AMS_CTRLY);
125   - if (enable)
126   - val |= 0x80;
127   - else
128   - val &= ~0x80;
129   - ams_i2c_write(AMS_CTRLY, val);
130   - }
131   -
132   - if (reg & AMS_IRQ_GLOBAL) {
133   - u8 val = ams_i2c_read(AMS_CTRLZ);
134   - if (enable)
135   - val |= 0x80;
136   - else
137   - val &= ~0x80;
138   - ams_i2c_write(AMS_CTRLZ, val);
139   - }
140   -}
141   -
142   -static void ams_i2c_clear_irq(enum ams_irq reg)
143   -{
144   - if (reg & AMS_IRQ_FREEFALL)
145   - ams_i2c_write(AMS_FREEFALL, 0);
146   -
147   - if (reg & AMS_IRQ_SHOCK)
148   - ams_i2c_write(AMS_SHOCK, 0);
149   -}
150   -
151   -static u8 ams_i2c_get_vendor(void)
152   -{
153   - return ams_i2c_read(AMS_VENDOR);
154   -}
155   -
156   -static void ams_i2c_get_xyz(s8 *x, s8 *y, s8 *z)
157   -{
158   - *x = ams_i2c_read(AMS_DATAX);
159   - *y = ams_i2c_read(AMS_DATAY);
160   - *z = ams_i2c_read(AMS_DATAZ);
161   -}
162   -
163   -static int ams_i2c_probe(struct i2c_client *client,
164   - const struct i2c_device_id *id)
165   -{
166   - int vmaj, vmin;
167   - int result;
168   -
169   - /* There can be only one */
170   - if (unlikely(ams_info.has_device))
171   - return -ENODEV;
172   -
173   - ams_info.i2c_client = client;
174   -
175   - if (ams_i2c_cmd(AMS_CMD_RESET)) {
176   - printk(KERN_INFO "ams: Failed to reset the device\n");
177   - return -ENODEV;
178   - }
179   -
180   - if (ams_i2c_cmd(AMS_CMD_START)) {
181   - printk(KERN_INFO "ams: Failed to start the device\n");
182   - return -ENODEV;
183   - }
184   -
185   - /* get version/vendor information */
186   - ams_i2c_write(AMS_CTRL1, 0x02);
187   - ams_i2c_write(AMS_CTRL2, 0x85);
188   - ams_i2c_write(AMS_CTRL3, 0x01);
189   -
190   - ams_i2c_cmd(AMS_CMD_READMEM);
191   -
192   - vmaj = ams_i2c_read(AMS_DATA1);
193   - vmin = ams_i2c_read(AMS_DATA2);
194   - if (vmaj != 1 || vmin != 52) {
195   - printk(KERN_INFO "ams: Incorrect device version (%d.%d)\n",
196   - vmaj, vmin);
197   - return -ENODEV;
198   - }
199   -
200   - ams_i2c_cmd(AMS_CMD_VERSION);
201   -
202   - vmaj = ams_i2c_read(AMS_DATA1);
203   - vmin = ams_i2c_read(AMS_DATA2);
204   - if (vmaj != 0 || vmin != 1) {
205   - printk(KERN_INFO "ams: Incorrect firmware version (%d.%d)\n",
206   - vmaj, vmin);
207   - return -ENODEV;
208   - }
209   -
210   - /* Disable interrupts */
211   - ams_i2c_set_irq(AMS_IRQ_ALL, 0);
212   -
213   - result = ams_sensor_attach();
214   - if (result < 0)
215   - return result;
216   -
217   - /* Set default values */
218   - ams_i2c_write(AMS_SENSLOW, 0x15);
219   - ams_i2c_write(AMS_SENSHIGH, 0x60);
220   - ams_i2c_write(AMS_CTRLX, 0x08);
221   - ams_i2c_write(AMS_CTRLY, 0x0F);
222   - ams_i2c_write(AMS_CTRLZ, 0x4F);
223   - ams_i2c_write(AMS_UNKNOWN1, 0x14);
224   -
225   - /* Clear interrupts */
226   - ams_i2c_clear_irq(AMS_IRQ_ALL);
227   -
228   - ams_info.has_device = 1;
229   -
230   - /* Enable interrupts */
231   - ams_i2c_set_irq(AMS_IRQ_ALL, 1);
232   -
233   - printk(KERN_INFO "ams: Found I2C based motion sensor\n");
234   -
235   - return 0;
236   -}
237   -
238   -static int ams_i2c_remove(struct i2c_client *client)
239   -{
240   - if (ams_info.has_device) {
241   - ams_sensor_detach();
242   -
243   - /* Disable interrupts */
244   - ams_i2c_set_irq(AMS_IRQ_ALL, 0);
245   -
246   - /* Clear interrupts */
247   - ams_i2c_clear_irq(AMS_IRQ_ALL);
248   -
249   - printk(KERN_INFO "ams: Unloading\n");
250   -
251   - ams_info.has_device = 0;
252   - }
253   -
254   - return 0;
255   -}
256   -
257   -static void ams_i2c_exit(void)
258   -{
259   - i2c_del_driver(&ams_i2c_driver);
260   -}
261   -
262   -int __init ams_i2c_init(struct device_node *np)
263   -{
264   - int result;
265   -
266   - /* Set implementation stuff */
267   - ams_info.of_node = np;
268   - ams_info.exit = ams_i2c_exit;
269   - ams_info.get_vendor = ams_i2c_get_vendor;
270   - ams_info.get_xyz = ams_i2c_get_xyz;
271   - ams_info.clear_irq = ams_i2c_clear_irq;
272   - ams_info.bustype = BUS_I2C;
273   -
274   - result = i2c_add_driver(&ams_i2c_driver);
275   -
276   - return result;
277   -}
drivers/hwmon/ams/ams-input.c
1   -/*
2   - * Apple Motion Sensor driver (joystick emulation)
3   - *
4   - * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
5   - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
6   - *
7   - * This program is free software; you can redistribute it and/or modify
8   - * it under the terms of the GNU General Public License as published by
9   - * the Free Software Foundation; either version 2 of the License, or
10   - * (at your option) any later version.
11   - */
12   -
13   -#include <linux/module.h>
14   -
15   -#include <linux/types.h>
16   -#include <linux/errno.h>
17   -#include <linux/init.h>
18   -#include <linux/delay.h>
19   -
20   -#include "ams.h"
21   -
22   -static unsigned int joystick;
23   -module_param(joystick, bool, S_IRUGO);
24   -MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
25   -
26   -static unsigned int invert;
27   -module_param(invert, bool, S_IWUSR | S_IRUGO);
28   -MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
29   -
30   -static DEFINE_MUTEX(ams_input_mutex);
31   -
32   -static void ams_idev_poll(struct input_polled_dev *dev)
33   -{
34   - struct input_dev *idev = dev->input;
35   - s8 x, y, z;
36   -
37   - mutex_lock(&ams_info.lock);
38   -
39   - ams_sensors(&x, &y, &z);
40   -
41   - x -= ams_info.xcalib;
42   - y -= ams_info.ycalib;
43   - z -= ams_info.zcalib;
44   -
45   - input_report_abs(idev, ABS_X, invert ? -x : x);
46   - input_report_abs(idev, ABS_Y, invert ? -y : y);
47   - input_report_abs(idev, ABS_Z, z);
48   -
49   - input_sync(idev);
50   -
51   - mutex_unlock(&ams_info.lock);
52   -}
53   -
54   -/* Call with ams_info.lock held! */
55   -static int ams_input_enable(void)
56   -{
57   - struct input_dev *input;
58   - s8 x, y, z;
59   - int error;
60   -
61   - ams_sensors(&x, &y, &z);
62   - ams_info.xcalib = x;
63   - ams_info.ycalib = y;
64   - ams_info.zcalib = z;
65   -
66   - ams_info.idev = input_allocate_polled_device();
67   - if (!ams_info.idev)
68   - return -ENOMEM;
69   -
70   - ams_info.idev->poll = ams_idev_poll;
71   - ams_info.idev->poll_interval = 25;
72   -
73   - input = ams_info.idev->input;
74   - input->name = "Apple Motion Sensor";
75   - input->id.bustype = ams_info.bustype;
76   - input->id.vendor = 0;
77   - input->dev.parent = &ams_info.of_dev->dev;
78   -
79   - input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
80   - input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
81   - input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
82   -
83   - set_bit(EV_ABS, input->evbit);
84   - set_bit(EV_KEY, input->evbit);
85   - set_bit(BTN_TOUCH, input->keybit);
86   -
87   - error = input_register_polled_device(ams_info.idev);
88   - if (error) {
89   - input_free_polled_device(ams_info.idev);
90   - ams_info.idev = NULL;
91   - return error;
92   - }
93   -
94   - joystick = 1;
95   -
96   - return 0;
97   -}
98   -
99   -static void ams_input_disable(void)
100   -{
101   - if (ams_info.idev) {
102   - input_unregister_polled_device(ams_info.idev);
103   - input_free_polled_device(ams_info.idev);
104   - ams_info.idev = NULL;
105   - }
106   -
107   - joystick = 0;
108   -}
109   -
110   -static ssize_t ams_input_show_joystick(struct device *dev,
111   - struct device_attribute *attr, char *buf)
112   -{
113   - return sprintf(buf, "%d\n", joystick);
114   -}
115   -
116   -static ssize_t ams_input_store_joystick(struct device *dev,
117   - struct device_attribute *attr, const char *buf, size_t count)
118   -{
119   - unsigned long enable;
120   - int error = 0;
121   -
122   - if (strict_strtoul(buf, 0, &enable) || enable > 1)
123   - return -EINVAL;
124   -
125   - mutex_lock(&ams_input_mutex);
126   -
127   - if (enable != joystick) {
128   - if (enable)
129   - error = ams_input_enable();
130   - else
131   - ams_input_disable();
132   - }
133   -
134   - mutex_unlock(&ams_input_mutex);
135   -
136   - return error ? error : count;
137   -}
138   -
139   -static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
140   - ams_input_show_joystick, ams_input_store_joystick);
141   -
142   -int ams_input_init(void)
143   -{
144   - if (joystick)
145   - ams_input_enable();
146   -
147   - return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
148   -}
149   -
150   -void ams_input_exit(void)
151   -{
152   - device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
153   -
154   - mutex_lock(&ams_input_mutex);
155   - ams_input_disable();
156   - mutex_unlock(&ams_input_mutex);
157   -}
drivers/hwmon/ams/ams-pmu.c
1   -/*
2   - * Apple Motion Sensor driver (PMU variant)
3   - *
4   - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
5   - *
6   - * This program is free software; you can redistribute it and/or modify
7   - * it under the terms of the GNU General Public License as published by
8   - * the Free Software Foundation; either version 2 of the License, or
9   - * (at your option) any later version.
10   - */
11   -
12   -#include <linux/module.h>
13   -#include <linux/types.h>
14   -#include <linux/errno.h>
15   -#include <linux/init.h>
16   -#include <linux/adb.h>
17   -#include <linux/pmu.h>
18   -
19   -#include "ams.h"
20   -
21   -/* Attitude */
22   -#define AMS_X 0x00
23   -#define AMS_Y 0x01
24   -#define AMS_Z 0x02
25   -
26   -/* Not exactly known, maybe chip vendor */
27   -#define AMS_VENDOR 0x03
28   -
29   -/* Freefall registers */
30   -#define AMS_FF_CLEAR 0x04
31   -#define AMS_FF_ENABLE 0x05
32   -#define AMS_FF_LOW_LIMIT 0x06
33   -#define AMS_FF_DEBOUNCE 0x07
34   -
35   -/* Shock registers */
36   -#define AMS_SHOCK_CLEAR 0x08
37   -#define AMS_SHOCK_ENABLE 0x09
38   -#define AMS_SHOCK_HIGH_LIMIT 0x0a
39   -#define AMS_SHOCK_DEBOUNCE 0x0b
40   -
41   -/* Global interrupt and power control register */
42   -#define AMS_CONTROL 0x0c
43   -
44   -static u8 ams_pmu_cmd;
45   -
46   -static void ams_pmu_req_complete(struct adb_request *req)
47   -{
48   - complete((struct completion *)req->arg);
49   -}
50   -
51   -/* Only call this function from task context */
52   -static void ams_pmu_set_register(u8 reg, u8 value)
53   -{
54   - static struct adb_request req;
55   - DECLARE_COMPLETION(req_complete);
56   -
57   - req.arg = &req_complete;
58   - if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
59   - return;
60   -
61   - wait_for_completion(&req_complete);
62   -}
63   -
64   -/* Only call this function from task context */
65   -static u8 ams_pmu_get_register(u8 reg)
66   -{
67   - static struct adb_request req;
68   - DECLARE_COMPLETION(req_complete);
69   -
70   - req.arg = &req_complete;
71   - if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
72   - return 0;
73   -
74   - wait_for_completion(&req_complete);
75   -
76   - if (req.reply_len > 0)
77   - return req.reply[0];
78   - else
79   - return 0;
80   -}
81   -
82   -/* Enables or disables the specified interrupts */
83   -static void ams_pmu_set_irq(enum ams_irq reg, char enable)
84   -{
85   - if (reg & AMS_IRQ_FREEFALL) {
86   - u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
87   - if (enable)
88   - val |= 0x80;
89   - else
90   - val &= ~0x80;
91   - ams_pmu_set_register(AMS_FF_ENABLE, val);
92   - }
93   -
94   - if (reg & AMS_IRQ_SHOCK) {
95   - u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
96   - if (enable)
97   - val |= 0x80;
98   - else
99   - val &= ~0x80;
100   - ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
101   - }
102   -
103   - if (reg & AMS_IRQ_GLOBAL) {
104   - u8 val = ams_pmu_get_register(AMS_CONTROL);
105   - if (enable)
106   - val |= 0x80;
107   - else
108   - val &= ~0x80;
109   - ams_pmu_set_register(AMS_CONTROL, val);
110   - }
111   -}
112   -
113   -static void ams_pmu_clear_irq(enum ams_irq reg)
114   -{
115   - if (reg & AMS_IRQ_FREEFALL)
116   - ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
117   -
118   - if (reg & AMS_IRQ_SHOCK)
119   - ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
120   -}
121   -
122   -static u8 ams_pmu_get_vendor(void)
123   -{
124   - return ams_pmu_get_register(AMS_VENDOR);
125   -}
126   -
127   -static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
128   -{
129   - *x = ams_pmu_get_register(AMS_X);
130   - *y = ams_pmu_get_register(AMS_Y);
131   - *z = ams_pmu_get_register(AMS_Z);
132   -}
133   -
134   -static void ams_pmu_exit(void)
135   -{
136   - ams_sensor_detach();
137   -
138   - /* Disable interrupts */
139   - ams_pmu_set_irq(AMS_IRQ_ALL, 0);
140   -
141   - /* Clear interrupts */
142   - ams_pmu_clear_irq(AMS_IRQ_ALL);
143   -
144   - ams_info.has_device = 0;
145   -
146   - printk(KERN_INFO "ams: Unloading\n");
147   -}
148   -
149   -int __init ams_pmu_init(struct device_node *np)
150   -{
151   - const u32 *prop;
152   - int result;
153   -
154   - /* Set implementation stuff */
155   - ams_info.of_node = np;
156   - ams_info.exit = ams_pmu_exit;
157   - ams_info.get_vendor = ams_pmu_get_vendor;
158   - ams_info.get_xyz = ams_pmu_get_xyz;
159   - ams_info.clear_irq = ams_pmu_clear_irq;
160   - ams_info.bustype = BUS_HOST;
161   -
162   - /* Get PMU command, should be 0x4e, but we can never know */
163   - prop = of_get_property(ams_info.of_node, "reg", NULL);
164   - if (!prop)
165   - return -ENODEV;
166   -
167   - ams_pmu_cmd = ((*prop) >> 8) & 0xff;
168   -
169   - /* Disable interrupts */
170   - ams_pmu_set_irq(AMS_IRQ_ALL, 0);
171   -
172   - /* Clear interrupts */
173   - ams_pmu_clear_irq(AMS_IRQ_ALL);
174   -
175   - result = ams_sensor_attach();
176   - if (result < 0)
177   - return result;
178   -
179   - /* Set default values */
180   - ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
181   - ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
182   - ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
183   -
184   - ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
185   - ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
186   - ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
187   -
188   - ams_pmu_set_register(AMS_CONTROL, 0x4f);
189   -
190   - /* Clear interrupts */
191   - ams_pmu_clear_irq(AMS_IRQ_ALL);
192   -
193   - ams_info.has_device = 1;
194   -
195   - /* Enable interrupts */
196   - ams_pmu_set_irq(AMS_IRQ_ALL, 1);
197   -
198   - printk(KERN_INFO "ams: Found PMU based motion sensor\n");
199   -
200   - return 0;
201   -}
drivers/hwmon/ams/ams.h
1   -#include <linux/i2c.h>
2   -#include <linux/input-polldev.h>
3   -#include <linux/kthread.h>
4   -#include <linux/mutex.h>
5   -#include <linux/spinlock.h>
6   -#include <linux/types.h>
7   -#include <linux/of_device.h>
8   -
9   -enum ams_irq {
10   - AMS_IRQ_FREEFALL = 0x01,
11   - AMS_IRQ_SHOCK = 0x02,
12   - AMS_IRQ_GLOBAL = 0x04,
13   - AMS_IRQ_ALL =
14   - AMS_IRQ_FREEFALL |
15   - AMS_IRQ_SHOCK |
16   - AMS_IRQ_GLOBAL,
17   -};
18   -
19   -struct ams {
20   - /* Locks */
21   - spinlock_t irq_lock;
22   - struct mutex lock;
23   -
24   - /* General properties */
25   - struct device_node *of_node;
26   - struct platform_device *of_dev;
27   - char has_device;
28   - char vflag;
29   - u32 orient1;
30   - u32 orient2;
31   -
32   - /* Interrupt worker */
33   - struct work_struct worker;
34   - u8 worker_irqs;
35   -
36   - /* Implementation
37   - *
38   - * Only call these functions with the main lock held.
39   - */
40   - void (*exit)(void);
41   -
42   - void (*get_xyz)(s8 *x, s8 *y, s8 *z);
43   - u8 (*get_vendor)(void);
44   -
45   - void (*clear_irq)(enum ams_irq reg);
46   -
47   -#ifdef CONFIG_SENSORS_AMS_I2C
48   - /* I2C properties */
49   - struct i2c_client *i2c_client;
50   -#endif
51   -
52   - /* Joystick emulation */
53   - struct input_polled_dev *idev;
54   - __u16 bustype;
55   -
56   - /* calibrated null values */
57   - int xcalib, ycalib, zcalib;
58   -};
59   -
60   -extern struct ams ams_info;
61   -
62   -extern void ams_sensors(s8 *x, s8 *y, s8 *z);
63   -extern int ams_sensor_attach(void);
64   -extern void ams_sensor_detach(void);
65   -
66   -extern int ams_pmu_init(struct device_node *np);
67   -extern int ams_i2c_init(struct device_node *np);
68   -
69   -extern int ams_input_init(void);
70   -extern void ams_input_exit(void);
drivers/macintosh/Kconfig
... ... @@ -256,5 +256,31 @@
256 256 This driver provides some support to control the front panel
257 257 blue LEDs "vu-meter" of the XServer macs.
258 258  
  259 +config SENSORS_AMS
  260 + tristate "Apple Motion Sensor driver"
  261 + depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
  262 + select INPUT_POLLDEV
  263 + help
  264 + Support for the motion sensor included in PowerBooks. Includes
  265 + implementations for PMU and I2C.
  266 +
  267 + This driver can also be built as a module. If so, the module
  268 + will be called ams.
  269 +
  270 +config SENSORS_AMS_PMU
  271 + bool "PMU variant"
  272 + depends on SENSORS_AMS && ADB_PMU
  273 + default y
  274 + help
  275 + PMU variant of motion sensor, found in late 2005 PowerBooks.
  276 +
  277 +config SENSORS_AMS_I2C
  278 + bool "I2C variant"
  279 + depends on SENSORS_AMS && I2C
  280 + default y
  281 + help
  282 + I2C variant of motion sensor, found in early 2005 PowerBooks and
  283 + iBooks.
  284 +
259 285 endif # MACINTOSH_DRIVERS
drivers/macintosh/Makefile
... ... @@ -48,4 +48,6 @@
48 48 windfarm_max6690_sensor.o \
49 49 windfarm_lm75_sensor.o windfarm_pid.o
50 50 obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o
  51 +
  52 +obj-$(CONFIG_SENSORS_AMS) += ams/
drivers/macintosh/ams/Makefile
  1 +#
  2 +# Makefile for Apple Motion Sensor driver
  3 +#
  4 +
  5 +ams-y := ams-core.o ams-input.o
  6 +ams-$(CONFIG_SENSORS_AMS_PMU) += ams-pmu.o
  7 +ams-$(CONFIG_SENSORS_AMS_I2C) += ams-i2c.o
  8 +obj-$(CONFIG_SENSORS_AMS) += ams.o
drivers/macintosh/ams/ams-core.c
  1 +/*
  2 + * Apple Motion Sensor driver
  3 + *
  4 + * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
  5 + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License as published by
  9 + * the Free Software Foundation; either version 2 of the License, or
  10 + * (at your option) any later version.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20 + */
  21 +
  22 +#include <linux/module.h>
  23 +#include <linux/types.h>
  24 +#include <linux/errno.h>
  25 +#include <linux/init.h>
  26 +#include <linux/of_platform.h>
  27 +#include <asm/pmac_pfunc.h>
  28 +
  29 +#include "ams.h"
  30 +
  31 +/* There is only one motion sensor per machine */
  32 +struct ams ams_info;
  33 +
  34 +static unsigned int verbose;
  35 +module_param(verbose, bool, 0644);
  36 +MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
  37 +
  38 +/* Call with ams_info.lock held! */
  39 +void ams_sensors(s8 *x, s8 *y, s8 *z)
  40 +{
  41 + u32 orient = ams_info.vflag? ams_info.orient1 : ams_info.orient2;
  42 +
  43 + if (orient & 0x80)
  44 + /* X and Y swapped */
  45 + ams_info.get_xyz(y, x, z);
  46 + else
  47 + ams_info.get_xyz(x, y, z);
  48 +
  49 + if (orient & 0x04)
  50 + *z = ~(*z);
  51 + if (orient & 0x02)
  52 + *y = ~(*y);
  53 + if (orient & 0x01)
  54 + *x = ~(*x);
  55 +}
  56 +
  57 +static ssize_t ams_show_current(struct device *dev,
  58 + struct device_attribute *attr, char *buf)
  59 +{
  60 + s8 x, y, z;
  61 +
  62 + mutex_lock(&ams_info.lock);
  63 + ams_sensors(&x, &y, &z);
  64 + mutex_unlock(&ams_info.lock);
  65 +
  66 + return snprintf(buf, PAGE_SIZE, "%d %d %d\n", x, y, z);
  67 +}
  68 +
  69 +static DEVICE_ATTR(current, S_IRUGO, ams_show_current, NULL);
  70 +
  71 +static void ams_handle_irq(void *data)
  72 +{
  73 + enum ams_irq irq = *((enum ams_irq *)data);
  74 +
  75 + spin_lock(&ams_info.irq_lock);
  76 +
  77 + ams_info.worker_irqs |= irq;
  78 + schedule_work(&ams_info.worker);
  79 +
  80 + spin_unlock(&ams_info.irq_lock);
  81 +}
  82 +
  83 +static enum ams_irq ams_freefall_irq_data = AMS_IRQ_FREEFALL;
  84 +static struct pmf_irq_client ams_freefall_client = {
  85 + .owner = THIS_MODULE,
  86 + .handler = ams_handle_irq,
  87 + .data = &ams_freefall_irq_data,
  88 +};
  89 +
  90 +static enum ams_irq ams_shock_irq_data = AMS_IRQ_SHOCK;
  91 +static struct pmf_irq_client ams_shock_client = {
  92 + .owner = THIS_MODULE,
  93 + .handler = ams_handle_irq,
  94 + .data = &ams_shock_irq_data,
  95 +};
  96 +
  97 +/* Once hard disk parking is implemented in the kernel, this function can
  98 + * trigger it.
  99 + */
  100 +static void ams_worker(struct work_struct *work)
  101 +{
  102 + unsigned long flags;
  103 + u8 irqs_to_clear;
  104 +
  105 + mutex_lock(&ams_info.lock);
  106 +
  107 + spin_lock_irqsave(&ams_info.irq_lock, flags);
  108 + irqs_to_clear = ams_info.worker_irqs;
  109 +
  110 + if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) {
  111 + if (verbose)
  112 + printk(KERN_INFO "ams: freefall detected!\n");
  113 +
  114 + ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL;
  115 + }
  116 +
  117 + if (ams_info.worker_irqs & AMS_IRQ_SHOCK) {
  118 + if (verbose)
  119 + printk(KERN_INFO "ams: shock detected!\n");
  120 +
  121 + ams_info.worker_irqs &= ~AMS_IRQ_SHOCK;
  122 + }
  123 +
  124 + spin_unlock_irqrestore(&ams_info.irq_lock, flags);
  125 +
  126 + ams_info.clear_irq(irqs_to_clear);
  127 +
  128 + mutex_unlock(&ams_info.lock);
  129 +}
  130 +
  131 +/* Call with ams_info.lock held! */
  132 +int ams_sensor_attach(void)
  133 +{
  134 + int result;
  135 + const u32 *prop;
  136 +
  137 + /* Get orientation */
  138 + prop = of_get_property(ams_info.of_node, "orientation", NULL);
  139 + if (!prop)
  140 + return -ENODEV;
  141 + ams_info.orient1 = *prop;
  142 + ams_info.orient2 = *(prop + 1);
  143 +
  144 + /* Register freefall interrupt handler */
  145 + result = pmf_register_irq_client(ams_info.of_node,
  146 + "accel-int-1",
  147 + &ams_freefall_client);
  148 + if (result < 0)
  149 + return -ENODEV;
  150 +
  151 + /* Reset saved irqs */
  152 + ams_info.worker_irqs = 0;
  153 +
  154 + /* Register shock interrupt handler */
  155 + result = pmf_register_irq_client(ams_info.of_node,
  156 + "accel-int-2",
  157 + &ams_shock_client);
  158 + if (result < 0)
  159 + goto release_freefall;
  160 +
  161 + /* Create device */
  162 + ams_info.of_dev = of_platform_device_create(ams_info.of_node, "ams", NULL);
  163 + if (!ams_info.of_dev) {
  164 + result = -ENODEV;
  165 + goto release_shock;
  166 + }
  167 +
  168 + /* Create attributes */
  169 + result = device_create_file(&ams_info.of_dev->dev, &dev_attr_current);
  170 + if (result)
  171 + goto release_of;
  172 +
  173 + ams_info.vflag = !!(ams_info.get_vendor() & 0x10);
  174 +
  175 + /* Init input device */
  176 + result = ams_input_init();
  177 + if (result)
  178 + goto release_device_file;
  179 +
  180 + return result;
  181 +release_device_file:
  182 + device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
  183 +release_of:
  184 + of_device_unregister(ams_info.of_dev);
  185 +release_shock:
  186 + pmf_unregister_irq_client(&ams_shock_client);
  187 +release_freefall:
  188 + pmf_unregister_irq_client(&ams_freefall_client);
  189 + return result;
  190 +}
  191 +
  192 +int __init ams_init(void)
  193 +{
  194 + struct device_node *np;
  195 +
  196 + spin_lock_init(&ams_info.irq_lock);
  197 + mutex_init(&ams_info.lock);
  198 + INIT_WORK(&ams_info.worker, ams_worker);
  199 +
  200 +#ifdef CONFIG_SENSORS_AMS_I2C
  201 + np = of_find_node_by_name(NULL, "accelerometer");
  202 + if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
  203 + /* Found I2C motion sensor */
  204 + return ams_i2c_init(np);
  205 +#endif
  206 +
  207 +#ifdef CONFIG_SENSORS_AMS_PMU
  208 + np = of_find_node_by_name(NULL, "sms");
  209 + if (np && of_device_is_compatible(np, "sms"))
  210 + /* Found PMU motion sensor */
  211 + return ams_pmu_init(np);
  212 +#endif
  213 + return -ENODEV;
  214 +}
  215 +
  216 +void ams_sensor_detach(void)
  217 +{
  218 + /* Remove input device */
  219 + ams_input_exit();
  220 +
  221 + /* Remove attributes */
  222 + device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
  223 +
  224 + /* Flush interrupt worker
  225 + *
  226 + * We do this after ams_info.exit(), because an interrupt might
  227 + * have arrived before disabling them.
  228 + */
  229 + flush_scheduled_work();
  230 +
  231 + /* Remove device */
  232 + of_device_unregister(ams_info.of_dev);
  233 +
  234 + /* Remove handler */
  235 + pmf_unregister_irq_client(&ams_shock_client);
  236 + pmf_unregister_irq_client(&ams_freefall_client);
  237 +}
  238 +
  239 +static void __exit ams_exit(void)
  240 +{
  241 + /* Shut down implementation */
  242 + ams_info.exit();
  243 +}
  244 +
  245 +MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
  246 +MODULE_DESCRIPTION("Apple Motion Sensor driver");
  247 +MODULE_LICENSE("GPL");
  248 +
  249 +module_init(ams_init);
  250 +module_exit(ams_exit);
drivers/macintosh/ams/ams-i2c.c
  1 +/*
  2 + * Apple Motion Sensor driver (I2C variant)
  3 + *
  4 + * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
  5 + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
  6 + *
  7 + * Clean room implementation based on the reverse engineered Mac OS X driver by
  8 + * Johannes Berg <johannes@sipsolutions.net>, documentation available at
  9 + * http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification
  10 + *
  11 + * This program is free software; you can redistribute it and/or modify
  12 + * it under the terms of the GNU General Public License as published by
  13 + * the Free Software Foundation; either version 2 of the License, or
  14 + * (at your option) any later version.
  15 + */
  16 +
  17 +#include <linux/module.h>
  18 +#include <linux/types.h>
  19 +#include <linux/errno.h>
  20 +#include <linux/init.h>
  21 +#include <linux/delay.h>
  22 +
  23 +#include "ams.h"
  24 +
  25 +/* AMS registers */
  26 +#define AMS_COMMAND 0x00 /* command register */
  27 +#define AMS_STATUS 0x01 /* status register */
  28 +#define AMS_CTRL1 0x02 /* read control 1 (number of values) */
  29 +#define AMS_CTRL2 0x03 /* read control 2 (offset?) */
  30 +#define AMS_CTRL3 0x04 /* read control 3 (size of each value?) */
  31 +#define AMS_DATA1 0x05 /* read data 1 */
  32 +#define AMS_DATA2 0x06 /* read data 2 */
  33 +#define AMS_DATA3 0x07 /* read data 3 */
  34 +#define AMS_DATA4 0x08 /* read data 4 */
  35 +#define AMS_DATAX 0x20 /* data X */
  36 +#define AMS_DATAY 0x21 /* data Y */
  37 +#define AMS_DATAZ 0x22 /* data Z */
  38 +#define AMS_FREEFALL 0x24 /* freefall int control */
  39 +#define AMS_SHOCK 0x25 /* shock int control */
  40 +#define AMS_SENSLOW 0x26 /* sensitivity low limit */
  41 +#define AMS_SENSHIGH 0x27 /* sensitivity high limit */
  42 +#define AMS_CTRLX 0x28 /* control X */
  43 +#define AMS_CTRLY 0x29 /* control Y */
  44 +#define AMS_CTRLZ 0x2A /* control Z */
  45 +#define AMS_UNKNOWN1 0x2B /* unknown 1 */
  46 +#define AMS_UNKNOWN2 0x2C /* unknown 2 */
  47 +#define AMS_UNKNOWN3 0x2D /* unknown 3 */
  48 +#define AMS_VENDOR 0x2E /* vendor */
  49 +
  50 +/* AMS commands - use with the AMS_COMMAND register */
  51 +enum ams_i2c_cmd {
  52 + AMS_CMD_NOOP = 0,
  53 + AMS_CMD_VERSION,
  54 + AMS_CMD_READMEM,
  55 + AMS_CMD_WRITEMEM,
  56 + AMS_CMD_ERASEMEM,
  57 + AMS_CMD_READEE,
  58 + AMS_CMD_WRITEEE,
  59 + AMS_CMD_RESET,
  60 + AMS_CMD_START,
  61 +};
  62 +
  63 +static int ams_i2c_probe(struct i2c_client *client,
  64 + const struct i2c_device_id *id);
  65 +static int ams_i2c_remove(struct i2c_client *client);
  66 +
  67 +static const struct i2c_device_id ams_id[] = {
  68 + { "ams", 0 },
  69 + { }
  70 +};
  71 +MODULE_DEVICE_TABLE(i2c, ams_id);
  72 +
  73 +static struct i2c_driver ams_i2c_driver = {
  74 + .driver = {
  75 + .name = "ams",
  76 + .owner = THIS_MODULE,
  77 + },
  78 + .probe = ams_i2c_probe,
  79 + .remove = ams_i2c_remove,
  80 + .id_table = ams_id,
  81 +};
  82 +
  83 +static s32 ams_i2c_read(u8 reg)
  84 +{
  85 + return i2c_smbus_read_byte_data(ams_info.i2c_client, reg);
  86 +}
  87 +
  88 +static int ams_i2c_write(u8 reg, u8 value)
  89 +{
  90 + return i2c_smbus_write_byte_data(ams_info.i2c_client, reg, value);
  91 +}
  92 +
  93 +static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
  94 +{
  95 + s32 result;
  96 + int count = 3;
  97 +
  98 + ams_i2c_write(AMS_COMMAND, cmd);
  99 + msleep(5);
  100 +
  101 + while (count--) {
  102 + result = ams_i2c_read(AMS_COMMAND);
  103 + if (result == 0 || result & 0x80)
  104 + return 0;
  105 +
  106 + schedule_timeout_uninterruptible(HZ / 20);
  107 + }
  108 +
  109 + return -1;
  110 +}
  111 +
  112 +static void ams_i2c_set_irq(enum ams_irq reg, char enable)
  113 +{
  114 + if (reg & AMS_IRQ_FREEFALL) {
  115 + u8 val = ams_i2c_read(AMS_CTRLX);
  116 + if (enable)
  117 + val |= 0x80;
  118 + else
  119 + val &= ~0x80;
  120 + ams_i2c_write(AMS_CTRLX, val);
  121 + }
  122 +
  123 + if (reg & AMS_IRQ_SHOCK) {
  124 + u8 val = ams_i2c_read(AMS_CTRLY);
  125 + if (enable)
  126 + val |= 0x80;
  127 + else
  128 + val &= ~0x80;
  129 + ams_i2c_write(AMS_CTRLY, val);
  130 + }
  131 +
  132 + if (reg & AMS_IRQ_GLOBAL) {
  133 + u8 val = ams_i2c_read(AMS_CTRLZ);
  134 + if (enable)
  135 + val |= 0x80;
  136 + else
  137 + val &= ~0x80;
  138 + ams_i2c_write(AMS_CTRLZ, val);
  139 + }
  140 +}
  141 +
  142 +static void ams_i2c_clear_irq(enum ams_irq reg)
  143 +{
  144 + if (reg & AMS_IRQ_FREEFALL)
  145 + ams_i2c_write(AMS_FREEFALL, 0);
  146 +
  147 + if (reg & AMS_IRQ_SHOCK)
  148 + ams_i2c_write(AMS_SHOCK, 0);
  149 +}
  150 +
  151 +static u8 ams_i2c_get_vendor(void)
  152 +{
  153 + return ams_i2c_read(AMS_VENDOR);
  154 +}
  155 +
  156 +static void ams_i2c_get_xyz(s8 *x, s8 *y, s8 *z)
  157 +{
  158 + *x = ams_i2c_read(AMS_DATAX);
  159 + *y = ams_i2c_read(AMS_DATAY);
  160 + *z = ams_i2c_read(AMS_DATAZ);
  161 +}
  162 +
  163 +static int ams_i2c_probe(struct i2c_client *client,
  164 + const struct i2c_device_id *id)
  165 +{
  166 + int vmaj, vmin;
  167 + int result;
  168 +
  169 + /* There can be only one */
  170 + if (unlikely(ams_info.has_device))
  171 + return -ENODEV;
  172 +
  173 + ams_info.i2c_client = client;
  174 +
  175 + if (ams_i2c_cmd(AMS_CMD_RESET)) {
  176 + printk(KERN_INFO "ams: Failed to reset the device\n");
  177 + return -ENODEV;
  178 + }
  179 +
  180 + if (ams_i2c_cmd(AMS_CMD_START)) {
  181 + printk(KERN_INFO "ams: Failed to start the device\n");
  182 + return -ENODEV;
  183 + }
  184 +
  185 + /* get version/vendor information */
  186 + ams_i2c_write(AMS_CTRL1, 0x02);
  187 + ams_i2c_write(AMS_CTRL2, 0x85);
  188 + ams_i2c_write(AMS_CTRL3, 0x01);
  189 +
  190 + ams_i2c_cmd(AMS_CMD_READMEM);
  191 +
  192 + vmaj = ams_i2c_read(AMS_DATA1);
  193 + vmin = ams_i2c_read(AMS_DATA2);
  194 + if (vmaj != 1 || vmin != 52) {
  195 + printk(KERN_INFO "ams: Incorrect device version (%d.%d)\n",
  196 + vmaj, vmin);
  197 + return -ENODEV;
  198 + }
  199 +
  200 + ams_i2c_cmd(AMS_CMD_VERSION);
  201 +
  202 + vmaj = ams_i2c_read(AMS_DATA1);
  203 + vmin = ams_i2c_read(AMS_DATA2);
  204 + if (vmaj != 0 || vmin != 1) {
  205 + printk(KERN_INFO "ams: Incorrect firmware version (%d.%d)\n",
  206 + vmaj, vmin);
  207 + return -ENODEV;
  208 + }
  209 +
  210 + /* Disable interrupts */
  211 + ams_i2c_set_irq(AMS_IRQ_ALL, 0);
  212 +
  213 + result = ams_sensor_attach();
  214 + if (result < 0)
  215 + return result;
  216 +
  217 + /* Set default values */
  218 + ams_i2c_write(AMS_SENSLOW, 0x15);
  219 + ams_i2c_write(AMS_SENSHIGH, 0x60);
  220 + ams_i2c_write(AMS_CTRLX, 0x08);
  221 + ams_i2c_write(AMS_CTRLY, 0x0F);
  222 + ams_i2c_write(AMS_CTRLZ, 0x4F);
  223 + ams_i2c_write(AMS_UNKNOWN1, 0x14);
  224 +
  225 + /* Clear interrupts */
  226 + ams_i2c_clear_irq(AMS_IRQ_ALL);
  227 +
  228 + ams_info.has_device = 1;
  229 +
  230 + /* Enable interrupts */
  231 + ams_i2c_set_irq(AMS_IRQ_ALL, 1);
  232 +
  233 + printk(KERN_INFO "ams: Found I2C based motion sensor\n");
  234 +
  235 + return 0;
  236 +}
  237 +
  238 +static int ams_i2c_remove(struct i2c_client *client)
  239 +{
  240 + if (ams_info.has_device) {
  241 + ams_sensor_detach();
  242 +
  243 + /* Disable interrupts */
  244 + ams_i2c_set_irq(AMS_IRQ_ALL, 0);
  245 +
  246 + /* Clear interrupts */
  247 + ams_i2c_clear_irq(AMS_IRQ_ALL);
  248 +
  249 + printk(KERN_INFO "ams: Unloading\n");
  250 +
  251 + ams_info.has_device = 0;
  252 + }
  253 +
  254 + return 0;
  255 +}
  256 +
  257 +static void ams_i2c_exit(void)
  258 +{
  259 + i2c_del_driver(&ams_i2c_driver);
  260 +}
  261 +
  262 +int __init ams_i2c_init(struct device_node *np)
  263 +{
  264 + int result;
  265 +
  266 + /* Set implementation stuff */
  267 + ams_info.of_node = np;
  268 + ams_info.exit = ams_i2c_exit;
  269 + ams_info.get_vendor = ams_i2c_get_vendor;
  270 + ams_info.get_xyz = ams_i2c_get_xyz;
  271 + ams_info.clear_irq = ams_i2c_clear_irq;
  272 + ams_info.bustype = BUS_I2C;
  273 +
  274 + result = i2c_add_driver(&ams_i2c_driver);
  275 +
  276 + return result;
  277 +}
drivers/macintosh/ams/ams-input.c
  1 +/*
  2 + * Apple Motion Sensor driver (joystick emulation)
  3 + *
  4 + * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
  5 + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License as published by
  9 + * the Free Software Foundation; either version 2 of the License, or
  10 + * (at your option) any later version.
  11 + */
  12 +
  13 +#include <linux/module.h>
  14 +
  15 +#include <linux/types.h>
  16 +#include <linux/errno.h>
  17 +#include <linux/init.h>
  18 +#include <linux/delay.h>
  19 +
  20 +#include "ams.h"
  21 +
  22 +static unsigned int joystick;
  23 +module_param(joystick, bool, S_IRUGO);
  24 +MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
  25 +
  26 +static unsigned int invert;
  27 +module_param(invert, bool, S_IWUSR | S_IRUGO);
  28 +MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
  29 +
  30 +static DEFINE_MUTEX(ams_input_mutex);
  31 +
  32 +static void ams_idev_poll(struct input_polled_dev *dev)
  33 +{
  34 + struct input_dev *idev = dev->input;
  35 + s8 x, y, z;
  36 +
  37 + mutex_lock(&ams_info.lock);
  38 +
  39 + ams_sensors(&x, &y, &z);
  40 +
  41 + x -= ams_info.xcalib;
  42 + y -= ams_info.ycalib;
  43 + z -= ams_info.zcalib;
  44 +
  45 + input_report_abs(idev, ABS_X, invert ? -x : x);
  46 + input_report_abs(idev, ABS_Y, invert ? -y : y);
  47 + input_report_abs(idev, ABS_Z, z);
  48 +
  49 + input_sync(idev);
  50 +
  51 + mutex_unlock(&ams_info.lock);
  52 +}
  53 +
  54 +/* Call with ams_info.lock held! */
  55 +static int ams_input_enable(void)
  56 +{
  57 + struct input_dev *input;
  58 + s8 x, y, z;
  59 + int error;
  60 +
  61 + ams_sensors(&x, &y, &z);
  62 + ams_info.xcalib = x;
  63 + ams_info.ycalib = y;
  64 + ams_info.zcalib = z;
  65 +
  66 + ams_info.idev = input_allocate_polled_device();
  67 + if (!ams_info.idev)
  68 + return -ENOMEM;
  69 +
  70 + ams_info.idev->poll = ams_idev_poll;
  71 + ams_info.idev->poll_interval = 25;
  72 +
  73 + input = ams_info.idev->input;
  74 + input->name = "Apple Motion Sensor";
  75 + input->id.bustype = ams_info.bustype;
  76 + input->id.vendor = 0;
  77 + input->dev.parent = &ams_info.of_dev->dev;
  78 +
  79 + input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
  80 + input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
  81 + input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
  82 +
  83 + set_bit(EV_ABS, input->evbit);
  84 + set_bit(EV_KEY, input->evbit);
  85 + set_bit(BTN_TOUCH, input->keybit);
  86 +
  87 + error = input_register_polled_device(ams_info.idev);
  88 + if (error) {
  89 + input_free_polled_device(ams_info.idev);
  90 + ams_info.idev = NULL;
  91 + return error;
  92 + }
  93 +
  94 + joystick = 1;
  95 +
  96 + return 0;
  97 +}
  98 +
  99 +static void ams_input_disable(void)
  100 +{
  101 + if (ams_info.idev) {
  102 + input_unregister_polled_device(ams_info.idev);
  103 + input_free_polled_device(ams_info.idev);
  104 + ams_info.idev = NULL;
  105 + }
  106 +
  107 + joystick = 0;
  108 +}
  109 +
  110 +static ssize_t ams_input_show_joystick(struct device *dev,
  111 + struct device_attribute *attr, char *buf)
  112 +{
  113 + return sprintf(buf, "%d\n", joystick);
  114 +}
  115 +
  116 +static ssize_t ams_input_store_joystick(struct device *dev,
  117 + struct device_attribute *attr, const char *buf, size_t count)
  118 +{
  119 + unsigned long enable;
  120 + int error = 0;
  121 +
  122 + if (strict_strtoul(buf, 0, &enable) || enable > 1)
  123 + return -EINVAL;
  124 +
  125 + mutex_lock(&ams_input_mutex);
  126 +
  127 + if (enable != joystick) {
  128 + if (enable)
  129 + error = ams_input_enable();
  130 + else
  131 + ams_input_disable();
  132 + }
  133 +
  134 + mutex_unlock(&ams_input_mutex);
  135 +
  136 + return error ? error : count;
  137 +}
  138 +
  139 +static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
  140 + ams_input_show_joystick, ams_input_store_joystick);
  141 +
  142 +int ams_input_init(void)
  143 +{
  144 + if (joystick)
  145 + ams_input_enable();
  146 +
  147 + return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
  148 +}
  149 +
  150 +void ams_input_exit(void)
  151 +{
  152 + device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
  153 +
  154 + mutex_lock(&ams_input_mutex);
  155 + ams_input_disable();
  156 + mutex_unlock(&ams_input_mutex);
  157 +}
drivers/macintosh/ams/ams-pmu.c
  1 +/*
  2 + * Apple Motion Sensor driver (PMU variant)
  3 + *
  4 + * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License as published by
  8 + * the Free Software Foundation; either version 2 of the License, or
  9 + * (at your option) any later version.
  10 + */
  11 +
  12 +#include <linux/module.h>
  13 +#include <linux/types.h>
  14 +#include <linux/errno.h>
  15 +#include <linux/init.h>
  16 +#include <linux/adb.h>
  17 +#include <linux/pmu.h>
  18 +
  19 +#include "ams.h"
  20 +
  21 +/* Attitude */
  22 +#define AMS_X 0x00
  23 +#define AMS_Y 0x01
  24 +#define AMS_Z 0x02
  25 +
  26 +/* Not exactly known, maybe chip vendor */
  27 +#define AMS_VENDOR 0x03
  28 +
  29 +/* Freefall registers */
  30 +#define AMS_FF_CLEAR 0x04
  31 +#define AMS_FF_ENABLE 0x05
  32 +#define AMS_FF_LOW_LIMIT 0x06
  33 +#define AMS_FF_DEBOUNCE 0x07
  34 +
  35 +/* Shock registers */
  36 +#define AMS_SHOCK_CLEAR 0x08
  37 +#define AMS_SHOCK_ENABLE 0x09
  38 +#define AMS_SHOCK_HIGH_LIMIT 0x0a
  39 +#define AMS_SHOCK_DEBOUNCE 0x0b
  40 +
  41 +/* Global interrupt and power control register */
  42 +#define AMS_CONTROL 0x0c
  43 +
  44 +static u8 ams_pmu_cmd;
  45 +
  46 +static void ams_pmu_req_complete(struct adb_request *req)
  47 +{
  48 + complete((struct completion *)req->arg);
  49 +}
  50 +
  51 +/* Only call this function from task context */
  52 +static void ams_pmu_set_register(u8 reg, u8 value)
  53 +{
  54 + static struct adb_request req;
  55 + DECLARE_COMPLETION(req_complete);
  56 +
  57 + req.arg = &req_complete;
  58 + if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
  59 + return;
  60 +
  61 + wait_for_completion(&req_complete);
  62 +}
  63 +
  64 +/* Only call this function from task context */
  65 +static u8 ams_pmu_get_register(u8 reg)
  66 +{
  67 + static struct adb_request req;
  68 + DECLARE_COMPLETION(req_complete);
  69 +
  70 + req.arg = &req_complete;
  71 + if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
  72 + return 0;
  73 +
  74 + wait_for_completion(&req_complete);
  75 +
  76 + if (req.reply_len > 0)
  77 + return req.reply[0];
  78 + else
  79 + return 0;
  80 +}
  81 +
  82 +/* Enables or disables the specified interrupts */
  83 +static void ams_pmu_set_irq(enum ams_irq reg, char enable)
  84 +{
  85 + if (reg & AMS_IRQ_FREEFALL) {
  86 + u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
  87 + if (enable)
  88 + val |= 0x80;
  89 + else
  90 + val &= ~0x80;
  91 + ams_pmu_set_register(AMS_FF_ENABLE, val);
  92 + }
  93 +
  94 + if (reg & AMS_IRQ_SHOCK) {
  95 + u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
  96 + if (enable)
  97 + val |= 0x80;
  98 + else
  99 + val &= ~0x80;
  100 + ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
  101 + }
  102 +
  103 + if (reg & AMS_IRQ_GLOBAL) {
  104 + u8 val = ams_pmu_get_register(AMS_CONTROL);
  105 + if (enable)
  106 + val |= 0x80;
  107 + else
  108 + val &= ~0x80;
  109 + ams_pmu_set_register(AMS_CONTROL, val);
  110 + }
  111 +}
  112 +
  113 +static void ams_pmu_clear_irq(enum ams_irq reg)
  114 +{
  115 + if (reg & AMS_IRQ_FREEFALL)
  116 + ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
  117 +
  118 + if (reg & AMS_IRQ_SHOCK)
  119 + ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
  120 +}
  121 +
  122 +static u8 ams_pmu_get_vendor(void)
  123 +{
  124 + return ams_pmu_get_register(AMS_VENDOR);
  125 +}
  126 +
  127 +static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
  128 +{
  129 + *x = ams_pmu_get_register(AMS_X);
  130 + *y = ams_pmu_get_register(AMS_Y);
  131 + *z = ams_pmu_get_register(AMS_Z);
  132 +}
  133 +
  134 +static void ams_pmu_exit(void)
  135 +{
  136 + ams_sensor_detach();
  137 +
  138 + /* Disable interrupts */
  139 + ams_pmu_set_irq(AMS_IRQ_ALL, 0);
  140 +
  141 + /* Clear interrupts */
  142 + ams_pmu_clear_irq(AMS_IRQ_ALL);
  143 +
  144 + ams_info.has_device = 0;
  145 +
  146 + printk(KERN_INFO "ams: Unloading\n");
  147 +}
  148 +
  149 +int __init ams_pmu_init(struct device_node *np)
  150 +{
  151 + const u32 *prop;
  152 + int result;
  153 +
  154 + /* Set implementation stuff */
  155 + ams_info.of_node = np;
  156 + ams_info.exit = ams_pmu_exit;
  157 + ams_info.get_vendor = ams_pmu_get_vendor;
  158 + ams_info.get_xyz = ams_pmu_get_xyz;
  159 + ams_info.clear_irq = ams_pmu_clear_irq;
  160 + ams_info.bustype = BUS_HOST;
  161 +
  162 + /* Get PMU command, should be 0x4e, but we can never know */
  163 + prop = of_get_property(ams_info.of_node, "reg", NULL);
  164 + if (!prop)
  165 + return -ENODEV;
  166 +
  167 + ams_pmu_cmd = ((*prop) >> 8) & 0xff;
  168 +
  169 + /* Disable interrupts */
  170 + ams_pmu_set_irq(AMS_IRQ_ALL, 0);
  171 +
  172 + /* Clear interrupts */
  173 + ams_pmu_clear_irq(AMS_IRQ_ALL);
  174 +
  175 + result = ams_sensor_attach();
  176 + if (result < 0)
  177 + return result;
  178 +
  179 + /* Set default values */
  180 + ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
  181 + ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
  182 + ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
  183 +
  184 + ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
  185 + ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
  186 + ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
  187 +
  188 + ams_pmu_set_register(AMS_CONTROL, 0x4f);
  189 +
  190 + /* Clear interrupts */
  191 + ams_pmu_clear_irq(AMS_IRQ_ALL);
  192 +
  193 + ams_info.has_device = 1;
  194 +
  195 + /* Enable interrupts */
  196 + ams_pmu_set_irq(AMS_IRQ_ALL, 1);
  197 +
  198 + printk(KERN_INFO "ams: Found PMU based motion sensor\n");
  199 +
  200 + return 0;
  201 +}
drivers/macintosh/ams/ams.h
  1 +#include <linux/i2c.h>
  2 +#include <linux/input-polldev.h>
  3 +#include <linux/kthread.h>
  4 +#include <linux/mutex.h>
  5 +#include <linux/spinlock.h>
  6 +#include <linux/types.h>
  7 +#include <linux/of_device.h>
  8 +
  9 +enum ams_irq {
  10 + AMS_IRQ_FREEFALL = 0x01,
  11 + AMS_IRQ_SHOCK = 0x02,
  12 + AMS_IRQ_GLOBAL = 0x04,
  13 + AMS_IRQ_ALL =
  14 + AMS_IRQ_FREEFALL |
  15 + AMS_IRQ_SHOCK |
  16 + AMS_IRQ_GLOBAL,
  17 +};
  18 +
  19 +struct ams {
  20 + /* Locks */
  21 + spinlock_t irq_lock;
  22 + struct mutex lock;
  23 +
  24 + /* General properties */
  25 + struct device_node *of_node;
  26 + struct platform_device *of_dev;
  27 + char has_device;
  28 + char vflag;
  29 + u32 orient1;
  30 + u32 orient2;
  31 +
  32 + /* Interrupt worker */
  33 + struct work_struct worker;
  34 + u8 worker_irqs;
  35 +
  36 + /* Implementation
  37 + *
  38 + * Only call these functions with the main lock held.
  39 + */
  40 + void (*exit)(void);
  41 +
  42 + void (*get_xyz)(s8 *x, s8 *y, s8 *z);
  43 + u8 (*get_vendor)(void);
  44 +
  45 + void (*clear_irq)(enum ams_irq reg);
  46 +
  47 +#ifdef CONFIG_SENSORS_AMS_I2C
  48 + /* I2C properties */
  49 + struct i2c_client *i2c_client;
  50 +#endif
  51 +
  52 + /* Joystick emulation */
  53 + struct input_polled_dev *idev;
  54 + __u16 bustype;
  55 +
  56 + /* calibrated null values */
  57 + int xcalib, ycalib, zcalib;
  58 +};
  59 +
  60 +extern struct ams ams_info;
  61 +
  62 +extern void ams_sensors(s8 *x, s8 *y, s8 *z);
  63 +extern int ams_sensor_attach(void);
  64 +extern void ams_sensor_detach(void);
  65 +
  66 +extern int ams_pmu_init(struct device_node *np);
  67 +extern int ams_i2c_init(struct device_node *np);
  68 +
  69 +extern int ams_input_init(void);
  70 +extern void ams_input_exit(void);