diff options
author | Luwei Zhou <b45643@freescale.com> | 2013-08-25 22:40:15 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:01:26 -0400 |
commit | d034a372f4e315db285b3cf90534ca82755d6373 (patch) | |
tree | 458a7f55253c2928108cc7858f7a585f48a113d9 | |
parent | 6003aa00d866f8183d0236da1b68f371ab5e90e4 (diff) |
ENGR00276501 sensor: Add mag3110 driver support
Add mag3110.c to support mag3110 sensor. Copy
the file from 3.0.35_4.1.0. Add Kconfig and
Makefile support.
Signed-off-by: Luwei Zhou <b45643@freescale.com>
-rw-r--r-- | drivers/hwmon/Kconfig | 9 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rwxr-xr-x | drivers/hwmon/mag3110.c | 611 |
3 files changed, 621 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f9838e66dde0..cac5aaa90a01 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1556,6 +1556,15 @@ config SENSORS_ATK0110 | |||
1556 | 1556 | ||
1557 | endif # ACPI | 1557 | endif # ACPI |
1558 | 1558 | ||
1559 | config SENSORS_MAG3110 | ||
1560 | tristate "Freescale MAG3110 e-compass sensor" | ||
1561 | depends on I2C && SYSFS | ||
1562 | help | ||
1563 | If you say yes here you get support for the Freescale MAG3110 | ||
1564 | e-compass sensor. | ||
1565 | This driver can also be built as a module. If so, the module | ||
1566 | will be called mag3110. | ||
1567 | |||
1559 | config MXC_MMA8451 | 1568 | config MXC_MMA8451 |
1560 | tristate "MMA8451 device driver" | 1569 | tristate "MMA8451 device driver" |
1561 | depends on I2C | 1570 | depends on I2C |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index bc7dfc032ef7..8f30a685567b 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -140,6 +140,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o | |||
140 | obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o | 140 | obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o |
141 | obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o | 141 | obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o |
142 | obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o | 142 | obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o |
143 | obj-$(CONFIG_SENSORS_MAG3110) += mag3110.o | ||
143 | obj-$(CONFIG_MXC_MMA8451) += mxc_mma8451.o | 144 | obj-$(CONFIG_MXC_MMA8451) += mxc_mma8451.o |
144 | 145 | ||
145 | obj-$(CONFIG_PMBUS) += pmbus/ | 146 | obj-$(CONFIG_PMBUS) += pmbus/ |
diff --git a/drivers/hwmon/mag3110.c b/drivers/hwmon/mag3110.c new file mode 100755 index 000000000000..9d7f617bcaef --- /dev/null +++ b/drivers/hwmon/mag3110.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | |||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | |||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/input-polldev.h> | ||
29 | #include <linux/hwmon.h> | ||
30 | #include <linux/input.h> | ||
31 | #include <linux/wait.h> | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/of.h> | ||
34 | #include <linux/regulator/consumer.h> | ||
35 | |||
36 | #define MAG3110_DRV_NAME "mag3110" | ||
37 | #define MAG3110_ID 0xC4 | ||
38 | #define MAG3110_XYZ_DATA_LEN 6 | ||
39 | #define MAG3110_STATUS_ZYXDR 0x08 | ||
40 | |||
41 | #define MAG3110_AC_MASK (0x01) | ||
42 | #define MAG3110_AC_OFFSET 0 | ||
43 | #define MAG3110_DR_MODE_MASK (0x7 << 5) | ||
44 | #define MAG3110_DR_MODE_OFFSET 5 | ||
45 | #define MAG3110_IRQ_USED 0 | ||
46 | |||
47 | #define POLL_INTERVAL_MAX 500 | ||
48 | #define POLL_INTERVAL 100 | ||
49 | #define INT_TIMEOUT 1000 | ||
50 | #define DEFAULT_POSITION 2 | ||
51 | /* register enum for mag3110 registers */ | ||
52 | enum { | ||
53 | MAG3110_DR_STATUS = 0x00, | ||
54 | MAG3110_OUT_X_MSB, | ||
55 | MAG3110_OUT_X_LSB, | ||
56 | MAG3110_OUT_Y_MSB, | ||
57 | MAG3110_OUT_Y_LSB, | ||
58 | MAG3110_OUT_Z_MSB, | ||
59 | MAG3110_OUT_Z_LSB, | ||
60 | MAG3110_WHO_AM_I, | ||
61 | |||
62 | MAG3110_OFF_X_MSB, | ||
63 | MAG3110_OFF_X_LSB, | ||
64 | MAG3110_OFF_Y_MSB, | ||
65 | MAG3110_OFF_Y_LSB, | ||
66 | MAG3110_OFF_Z_MSB, | ||
67 | MAG3110_OFF_Z_LSB, | ||
68 | |||
69 | MAG3110_DIE_TEMP, | ||
70 | |||
71 | MAG3110_CTRL_REG1 = 0x10, | ||
72 | MAG3110_CTRL_REG2, | ||
73 | }; | ||
74 | enum { | ||
75 | MAG_STANDBY, | ||
76 | MAG_ACTIVED | ||
77 | }; | ||
78 | struct mag3110_data { | ||
79 | struct i2c_client *client; | ||
80 | struct input_polled_dev *poll_dev; | ||
81 | struct device *hwmon_dev; | ||
82 | wait_queue_head_t waitq; | ||
83 | bool data_ready; | ||
84 | u8 ctl_reg1; | ||
85 | int active; | ||
86 | int position; | ||
87 | }; | ||
88 | static short MAGHAL[8][3][3] = { | ||
89 | { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, | ||
90 | { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }, | ||
91 | { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} }, | ||
92 | { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} }, | ||
93 | |||
94 | { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} }, | ||
95 | { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} }, | ||
96 | { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, | ||
97 | { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} }, | ||
98 | }; | ||
99 | |||
100 | static struct mag3110_data *mag3110_pdata; | ||
101 | /*! | ||
102 | * This function do one mag3110 register read. | ||
103 | */ | ||
104 | static DEFINE_MUTEX(mag3110_lock); | ||
105 | static int mag3110_adjust_position(short *x, short *y, short *z) | ||
106 | { | ||
107 | short rawdata[3], data[3]; | ||
108 | int i, j; | ||
109 | int position = mag3110_pdata->position; | ||
110 | if (position < 0 || position > 7) | ||
111 | position = 0; | ||
112 | rawdata[0] = *x; | ||
113 | rawdata[1] = *y; | ||
114 | rawdata[2] = *z; | ||
115 | for (i = 0; i < 3; i++) { | ||
116 | data[i] = 0; | ||
117 | for (j = 0; j < 3; j++) | ||
118 | data[i] += rawdata[j] * MAGHAL[position][i][j]; | ||
119 | } | ||
120 | *x = data[0]; | ||
121 | *y = data[1]; | ||
122 | *z = data[2]; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int mag3110_read_reg(struct i2c_client *client, u8 reg) | ||
127 | { | ||
128 | return i2c_smbus_read_byte_data(client, reg); | ||
129 | } | ||
130 | |||
131 | /*! | ||
132 | * This function do one mag3110 register write. | ||
133 | */ | ||
134 | static int mag3110_write_reg(struct i2c_client *client, u8 reg, char value) | ||
135 | { | ||
136 | int ret; | ||
137 | |||
138 | ret = i2c_smbus_write_byte_data(client, reg, value); | ||
139 | if (ret < 0) | ||
140 | dev_err(&client->dev, "i2c write failed\n"); | ||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | /*! | ||
145 | * This function do multiple mag3110 registers read. | ||
146 | */ | ||
147 | static int mag3110_read_block_data(struct i2c_client *client, u8 reg, | ||
148 | int count, u8 *addr) | ||
149 | { | ||
150 | if (i2c_smbus_read_i2c_block_data(client, reg, count, addr) < count) { | ||
151 | dev_err(&client->dev, "i2c block read failed\n"); | ||
152 | return -1; | ||
153 | } | ||
154 | |||
155 | return count; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Initialization function | ||
160 | */ | ||
161 | static int mag3110_init_client(struct i2c_client *client) | ||
162 | { | ||
163 | int val, ret; | ||
164 | |||
165 | /* enable automatic resets */ | ||
166 | val = 0x80; | ||
167 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG2, val); | ||
168 | |||
169 | /* set default data rate to 10HZ */ | ||
170 | val = mag3110_read_reg(client, MAG3110_CTRL_REG1); | ||
171 | val |= (0x0 << MAG3110_DR_MODE_OFFSET); | ||
172 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, val); | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | /*************************************************************** | ||
178 | * | ||
179 | * read sensor data from mag3110 | ||
180 | * | ||
181 | ***************************************************************/ | ||
182 | static int mag3110_read_data(short *x, short *y, short *z) | ||
183 | { | ||
184 | struct mag3110_data *data; | ||
185 | int retry = 3; | ||
186 | u8 tmp_data[MAG3110_XYZ_DATA_LEN]; | ||
187 | int result; | ||
188 | if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY) | ||
189 | return -EINVAL; | ||
190 | |||
191 | data = mag3110_pdata; | ||
192 | #if MAG3110_IRQ_USED | ||
193 | if (!wait_event_interruptible_timeout | ||
194 | (data->waitq, data->data_ready != 0, | ||
195 | msecs_to_jiffies(INT_TIMEOUT))) { | ||
196 | dev_dbg(&data->client->dev, "interrupt not received\n"); | ||
197 | return -ETIME; | ||
198 | } | ||
199 | #else | ||
200 | do { | ||
201 | msleep(1); | ||
202 | result = i2c_smbus_read_byte_data(data->client, | ||
203 | MAG3110_DR_STATUS); | ||
204 | retry--; | ||
205 | } while (!(result & MAG3110_STATUS_ZYXDR) && retry > 0); | ||
206 | /* Clear data_ready flag after data is read out */ | ||
207 | if (retry == 0) | ||
208 | return -EINVAL; | ||
209 | #endif | ||
210 | |||
211 | data->data_ready = 0; | ||
212 | |||
213 | if (mag3110_read_block_data(data->client, | ||
214 | MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN, | ||
215 | tmp_data) < 0) | ||
216 | return -1; | ||
217 | |||
218 | *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; | ||
219 | *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; | ||
220 | *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static void report_abs(void) | ||
226 | { | ||
227 | struct input_dev *idev; | ||
228 | short x, y, z; | ||
229 | |||
230 | mutex_lock(&mag3110_lock); | ||
231 | if (mag3110_read_data(&x, &y, &z) != 0) | ||
232 | goto out; | ||
233 | mag3110_adjust_position(&x, &y, &z); | ||
234 | idev = mag3110_pdata->poll_dev->input; | ||
235 | input_report_abs(idev, ABS_X, x); | ||
236 | input_report_abs(idev, ABS_Y, y); | ||
237 | input_report_abs(idev, ABS_Z, z); | ||
238 | input_sync(idev); | ||
239 | out: | ||
240 | mutex_unlock(&mag3110_lock); | ||
241 | } | ||
242 | |||
243 | static void mag3110_dev_poll(struct input_polled_dev *dev) | ||
244 | { | ||
245 | report_abs(); | ||
246 | } | ||
247 | |||
248 | #if MAG3110_IRQ_USED | ||
249 | static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) | ||
250 | { | ||
251 | mag3110_pdata->data_ready = 1; | ||
252 | wake_up_interruptible(&mag3110_pdata->waitq); | ||
253 | |||
254 | return IRQ_HANDLED; | ||
255 | } | ||
256 | #endif | ||
257 | static ssize_t mag3110_enable_show(struct device *dev, | ||
258 | struct device_attribute *attr, char *buf) | ||
259 | { | ||
260 | struct i2c_client *client; | ||
261 | int val; | ||
262 | mutex_lock(&mag3110_lock); | ||
263 | client = mag3110_pdata->client; | ||
264 | val = mag3110_read_reg(client, MAG3110_CTRL_REG1) & MAG3110_AC_MASK; | ||
265 | |||
266 | mutex_unlock(&mag3110_lock); | ||
267 | return sprintf(buf, "%d\n", val); | ||
268 | } | ||
269 | |||
270 | static ssize_t mag3110_enable_store(struct device *dev, | ||
271 | struct device_attribute *attr, | ||
272 | const char *buf, size_t count) | ||
273 | { | ||
274 | struct i2c_client *client; | ||
275 | int reg, ret; | ||
276 | long enable; | ||
277 | u8 tmp_data[MAG3110_XYZ_DATA_LEN]; | ||
278 | |||
279 | ret = strict_strtol(buf, 10, &enable); | ||
280 | if (ret) { | ||
281 | dev_err(dev, "string to long error\n"); | ||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | mutex_lock(&mag3110_lock); | ||
286 | client = mag3110_pdata->client; | ||
287 | reg = mag3110_read_reg(client, MAG3110_CTRL_REG1); | ||
288 | if (enable && mag3110_pdata->active == MAG_STANDBY) { | ||
289 | reg |= MAG3110_AC_MASK; | ||
290 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); | ||
291 | if (!ret) | ||
292 | mag3110_pdata->active = MAG_ACTIVED; | ||
293 | } else if (!enable && mag3110_pdata->active == MAG_ACTIVED) { | ||
294 | reg &= ~MAG3110_AC_MASK; | ||
295 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); | ||
296 | if (!ret) | ||
297 | mag3110_pdata->active = MAG_STANDBY; | ||
298 | } | ||
299 | |||
300 | if (mag3110_pdata->active == MAG_ACTIVED) { | ||
301 | msleep(100); | ||
302 | /* Read out MSB data to clear interrupt flag automatically */ | ||
303 | mag3110_read_block_data(client, MAG3110_OUT_X_MSB, | ||
304 | MAG3110_XYZ_DATA_LEN, tmp_data); | ||
305 | } | ||
306 | mutex_unlock(&mag3110_lock); | ||
307 | return count; | ||
308 | } | ||
309 | |||
310 | static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, | ||
311 | mag3110_enable_show, mag3110_enable_store); | ||
312 | |||
313 | static ssize_t mag3110_dr_mode_show(struct device *dev, | ||
314 | struct device_attribute *attr, char *buf) | ||
315 | { | ||
316 | struct i2c_client *client; | ||
317 | int val; | ||
318 | |||
319 | client = mag3110_pdata->client; | ||
320 | val = (mag3110_read_reg(client, MAG3110_CTRL_REG1) | ||
321 | & MAG3110_DR_MODE_MASK) >> MAG3110_DR_MODE_OFFSET; | ||
322 | |||
323 | return sprintf(buf, "%d\n", val); | ||
324 | } | ||
325 | |||
326 | static ssize_t mag3110_dr_mode_store(struct device *dev, | ||
327 | struct device_attribute *attr, | ||
328 | const char *buf, size_t count) | ||
329 | { | ||
330 | struct i2c_client *client; | ||
331 | int reg, ret; | ||
332 | unsigned long val; | ||
333 | |||
334 | /* This must be done when mag3110 is disabled */ | ||
335 | if ((strict_strtoul(buf, 10, &val) < 0) || (val > 7)) | ||
336 | return -EINVAL; | ||
337 | |||
338 | client = mag3110_pdata->client; | ||
339 | reg = mag3110_read_reg(client, MAG3110_CTRL_REG1) & | ||
340 | ~MAG3110_DR_MODE_MASK; | ||
341 | reg |= (val << MAG3110_DR_MODE_OFFSET); | ||
342 | /* MAG3110_CTRL_REG1 bit 5-7: data rate mode */ | ||
343 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); | ||
344 | if (ret < 0) | ||
345 | return ret; | ||
346 | |||
347 | return count; | ||
348 | } | ||
349 | |||
350 | static DEVICE_ATTR(dr_mode, S_IWUSR | S_IRUGO, | ||
351 | mag3110_dr_mode_show, mag3110_dr_mode_store); | ||
352 | |||
353 | static ssize_t mag3110_position_show(struct device *dev, | ||
354 | struct device_attribute *attr, char *buf) | ||
355 | { | ||
356 | int val; | ||
357 | mutex_lock(&mag3110_lock); | ||
358 | val = mag3110_pdata->position; | ||
359 | mutex_unlock(&mag3110_lock); | ||
360 | return sprintf(buf, "%d\n", val); | ||
361 | } | ||
362 | |||
363 | static ssize_t mag3110_position_store(struct device *dev, | ||
364 | struct device_attribute *attr, | ||
365 | const char *buf, size_t count) | ||
366 | { | ||
367 | long position; | ||
368 | int ret; | ||
369 | ret = strict_strtol(buf, 10, &position); | ||
370 | if (ret) { | ||
371 | dev_err(dev, "string to long error\n"); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | mutex_lock(&mag3110_lock); | ||
376 | mag3110_pdata->position = (int)position; | ||
377 | mutex_unlock(&mag3110_lock); | ||
378 | return count; | ||
379 | } | ||
380 | |||
381 | static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, | ||
382 | mag3110_position_show, mag3110_position_store); | ||
383 | |||
384 | static struct attribute *mag3110_attributes[] = { | ||
385 | &dev_attr_enable.attr, | ||
386 | &dev_attr_dr_mode.attr, | ||
387 | &dev_attr_position.attr, | ||
388 | NULL | ||
389 | }; | ||
390 | |||
391 | static const struct attribute_group mag3110_attr_group = { | ||
392 | .attrs = mag3110_attributes, | ||
393 | }; | ||
394 | |||
395 | static int mag3110_probe(struct i2c_client *client, | ||
396 | const struct i2c_device_id *id) | ||
397 | { | ||
398 | struct i2c_adapter *adapter; | ||
399 | struct input_dev *idev; | ||
400 | struct mag3110_data *data; | ||
401 | int ret = 0; | ||
402 | struct regulator *vdd, *vdd_io; | ||
403 | u32 pos = 0; | ||
404 | struct device_node *of_node = client->dev.of_node; | ||
405 | vdd = NULL; | ||
406 | vdd_io = NULL; | ||
407 | |||
408 | vdd = devm_regulator_get(&client->dev, "vdd"); | ||
409 | if (!IS_ERR(vdd)) { | ||
410 | ret = regulator_enable(vdd); | ||
411 | if (ret) { | ||
412 | dev_err(&client->dev, "vdd set voltage error\n"); | ||
413 | return ret; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | vdd_io = devm_regulator_get(&client->dev, "vddio"); | ||
418 | if (!IS_ERR(vdd_io)) { | ||
419 | ret = regulator_enable(vdd_io); | ||
420 | if (ret) { | ||
421 | dev_err(&client->dev, "vddio set voltage error\n"); | ||
422 | return ret; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | adapter = to_i2c_adapter(client->dev.parent); | ||
427 | if (!i2c_check_functionality(adapter, | ||
428 | I2C_FUNC_SMBUS_BYTE | | ||
429 | I2C_FUNC_SMBUS_BYTE_DATA | | ||
430 | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
431 | return -EIO; | ||
432 | |||
433 | dev_info(&client->dev, "check mag3110 chip ID\n"); | ||
434 | ret = mag3110_read_reg(client, MAG3110_WHO_AM_I); | ||
435 | |||
436 | if (MAG3110_ID != ret) { | ||
437 | dev_err(&client->dev, | ||
438 | "read chip ID 0x%x is not equal to 0x%x!\n", ret, | ||
439 | MAG3110_ID); | ||
440 | return -EINVAL; | ||
441 | } | ||
442 | data = kzalloc(sizeof(struct mag3110_data), GFP_KERNEL); | ||
443 | if (!data) | ||
444 | return -ENOMEM; | ||
445 | data->client = client; | ||
446 | i2c_set_clientdata(client, data); | ||
447 | /* Init queue */ | ||
448 | init_waitqueue_head(&data->waitq); | ||
449 | |||
450 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
451 | if (IS_ERR(data->hwmon_dev)) { | ||
452 | dev_err(&client->dev, "hwmon register failed!\n"); | ||
453 | ret = PTR_ERR(data->hwmon_dev); | ||
454 | goto error_rm_dev_sysfs; | ||
455 | } | ||
456 | |||
457 | /*input poll device register */ | ||
458 | data->poll_dev = input_allocate_polled_device(); | ||
459 | if (!data->poll_dev) { | ||
460 | dev_err(&client->dev, "alloc poll device failed!\n"); | ||
461 | ret = -ENOMEM; | ||
462 | goto error_rm_hwmon_dev; | ||
463 | } | ||
464 | data->poll_dev->poll = mag3110_dev_poll; | ||
465 | data->poll_dev->poll_interval = POLL_INTERVAL; | ||
466 | data->poll_dev->poll_interval_max = POLL_INTERVAL_MAX; | ||
467 | idev = data->poll_dev->input; | ||
468 | idev->name = MAG3110_DRV_NAME; | ||
469 | idev->id.bustype = BUS_I2C; | ||
470 | idev->evbit[0] = BIT_MASK(EV_ABS); | ||
471 | input_set_abs_params(idev, ABS_X, -15000, 15000, 0, 0); | ||
472 | input_set_abs_params(idev, ABS_Y, -15000, 15000, 0, 0); | ||
473 | input_set_abs_params(idev, ABS_Z, -15000, 15000, 0, 0); | ||
474 | ret = input_register_polled_device(data->poll_dev); | ||
475 | if (ret) { | ||
476 | dev_err(&client->dev, "register poll device failed!\n"); | ||
477 | goto error_free_poll_dev; | ||
478 | } | ||
479 | |||
480 | /*create device group in sysfs as user interface */ | ||
481 | ret = sysfs_create_group(&idev->dev.kobj, &mag3110_attr_group); | ||
482 | if (ret) { | ||
483 | dev_err(&client->dev, "create device file failed!\n"); | ||
484 | ret = -EINVAL; | ||
485 | goto error_rm_poll_dev; | ||
486 | } | ||
487 | /* set irq type to edge rising */ | ||
488 | #if MAG3110_IRQ_USED | ||
489 | ret = request_irq(client->irq, mag3110_irq_handler, | ||
490 | IRQF_TRIGGER_RISING, client->dev.driver->name, idev); | ||
491 | if (ret < 0) { | ||
492 | dev_err(&client->dev, "failed to register irq %d!\n", | ||
493 | client->irq); | ||
494 | goto error_rm_dev_sysfs; | ||
495 | } | ||
496 | #endif | ||
497 | /* Initialize mag3110 chip */ | ||
498 | mag3110_init_client(client); | ||
499 | mag3110_pdata = data; | ||
500 | mag3110_pdata->active = MAG_STANDBY; | ||
501 | ret = of_property_read_u32(of_node, "position", &pos); | ||
502 | if (ret) | ||
503 | pos = DEFAULT_POSITION; | ||
504 | mag3110_pdata->position = (int)pos; | ||
505 | dev_info(&client->dev, "mag3110 is probed\n"); | ||
506 | return 0; | ||
507 | error_rm_dev_sysfs: | ||
508 | sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); | ||
509 | error_rm_poll_dev: | ||
510 | input_unregister_polled_device(data->poll_dev); | ||
511 | error_free_poll_dev: | ||
512 | input_free_polled_device(data->poll_dev); | ||
513 | error_rm_hwmon_dev: | ||
514 | hwmon_device_unregister(data->hwmon_dev); | ||
515 | |||
516 | kfree(data); | ||
517 | mag3110_pdata = NULL; | ||
518 | |||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | static int mag3110_remove(struct i2c_client *client) | ||
523 | { | ||
524 | struct mag3110_data *data; | ||
525 | int ret; | ||
526 | |||
527 | data = i2c_get_clientdata(client); | ||
528 | |||
529 | data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); | ||
530 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, | ||
531 | data->ctl_reg1 & ~MAG3110_AC_MASK); | ||
532 | |||
533 | free_irq(client->irq, data); | ||
534 | input_unregister_polled_device(data->poll_dev); | ||
535 | input_free_polled_device(data->poll_dev); | ||
536 | hwmon_device_unregister(data->hwmon_dev); | ||
537 | sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); | ||
538 | kfree(data); | ||
539 | mag3110_pdata = NULL; | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | #ifdef CONFIG_PM | ||
545 | static int mag3110_suspend(struct i2c_client *client, pm_message_t mesg) | ||
546 | { | ||
547 | int ret = 0; | ||
548 | struct mag3110_data *data = i2c_get_clientdata(client); | ||
549 | if (data->active == MAG_ACTIVED) { | ||
550 | data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); | ||
551 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, | ||
552 | data->ctl_reg1 & ~MAG3110_AC_MASK); | ||
553 | } | ||
554 | return ret; | ||
555 | } | ||
556 | |||
557 | static int mag3110_resume(struct i2c_client *client) | ||
558 | { | ||
559 | int ret = 0; | ||
560 | u8 tmp_data[MAG3110_XYZ_DATA_LEN]; | ||
561 | struct mag3110_data *data = i2c_get_clientdata(client); | ||
562 | if (data->active == MAG_ACTIVED) { | ||
563 | ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, | ||
564 | data->ctl_reg1); | ||
565 | |||
566 | if (data->ctl_reg1 & MAG3110_AC_MASK) { | ||
567 | /* Read out MSB data to clear interrupt | ||
568 | flag automatically */ | ||
569 | mag3110_read_block_data(client, MAG3110_OUT_X_MSB, | ||
570 | MAG3110_XYZ_DATA_LEN, tmp_data); | ||
571 | } | ||
572 | } | ||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | #else | ||
577 | #define mag3110_suspend NULL | ||
578 | #define mag3110_resume NULL | ||
579 | #endif /* CONFIG_PM */ | ||
580 | |||
581 | static const struct i2c_device_id mag3110_id[] = { | ||
582 | {MAG3110_DRV_NAME, 0}, | ||
583 | {} | ||
584 | }; | ||
585 | |||
586 | MODULE_DEVICE_TABLE(i2c, mag3110_id); | ||
587 | static struct i2c_driver mag3110_driver = { | ||
588 | .driver = {.name = MAG3110_DRV_NAME, | ||
589 | .owner = THIS_MODULE,}, | ||
590 | .suspend = mag3110_suspend, | ||
591 | .resume = mag3110_resume, | ||
592 | .probe = mag3110_probe, | ||
593 | .remove = mag3110_remove, | ||
594 | .id_table = mag3110_id, | ||
595 | }; | ||
596 | |||
597 | static int __init mag3110_init(void) | ||
598 | { | ||
599 | return i2c_add_driver(&mag3110_driver); | ||
600 | } | ||
601 | |||
602 | static void __exit mag3110_exit(void) | ||
603 | { | ||
604 | i2c_del_driver(&mag3110_driver); | ||
605 | } | ||
606 | |||
607 | module_init(mag3110_init); | ||
608 | module_exit(mag3110_exit); | ||
609 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
610 | MODULE_DESCRIPTION("Freescale mag3110 3-axis magnetometer driver"); | ||
611 | MODULE_LICENSE("GPL"); | ||