aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorLuwei Zhou <b45643@freescale.com>2014-03-31 02:05:23 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:12 -0400
commita6280e9bb35440f51eb090898dcede82c4e2994e (patch)
tree3f709ca30eb45b8a18543b330471b92a0b711231 /drivers/hwmon
parent1ddd70da4ce5558d0b0a76cadae263a648628d7a (diff)
ENGR00306134-1: hwmon: mag3110 Enable mag3110 driver for i.MX6SX-SDB platform
The mag3110 driver can support irq mode and polling mode. On i.MX6SX-SDB platorm, mag3110 sensor and other sensor share the same GPIO interrutp line. The main modification: * Modify the driver to support irq working mode. * Add shared interrupt support in the driver. * Fix the clear interrupt flag issue. Signed-off-by: Luwei Zhou <b45643@freescale.com>
Diffstat (limited to 'drivers/hwmon')
-rwxr-xr-xdrivers/hwmon/mag3110.c59
1 files changed, 44 insertions, 15 deletions
diff --git a/drivers/hwmon/mag3110.c b/drivers/hwmon/mag3110.c
index 9d7f617bcaef..a8d80fa46dfe 100755
--- a/drivers/hwmon/mag3110.c
+++ b/drivers/hwmon/mag3110.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 3 * Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License as published by
@@ -37,12 +37,11 @@
37#define MAG3110_ID 0xC4 37#define MAG3110_ID 0xC4
38#define MAG3110_XYZ_DATA_LEN 6 38#define MAG3110_XYZ_DATA_LEN 6
39#define MAG3110_STATUS_ZYXDR 0x08 39#define MAG3110_STATUS_ZYXDR 0x08
40 40#define MAG3110_IRQ_USED 1
41#define MAG3110_AC_MASK (0x01) 41#define MAG3110_AC_MASK (0x01)
42#define MAG3110_AC_OFFSET 0 42#define MAG3110_AC_OFFSET 0
43#define MAG3110_DR_MODE_MASK (0x7 << 5) 43#define MAG3110_DR_MODE_MASK (0x7 << 5)
44#define MAG3110_DR_MODE_OFFSET 5 44#define MAG3110_DR_MODE_OFFSET 5
45#define MAG3110_IRQ_USED 0
46 45
47#define POLL_INTERVAL_MAX 500 46#define POLL_INTERVAL_MAX 500
48#define POLL_INTERVAL 100 47#define POLL_INTERVAL 100
@@ -182,9 +181,11 @@ static int mag3110_init_client(struct i2c_client *client)
182static int mag3110_read_data(short *x, short *y, short *z) 181static int mag3110_read_data(short *x, short *y, short *z)
183{ 182{
184 struct mag3110_data *data; 183 struct mag3110_data *data;
185 int retry = 3;
186 u8 tmp_data[MAG3110_XYZ_DATA_LEN]; 184 u8 tmp_data[MAG3110_XYZ_DATA_LEN];
185#if !MAG3110_IRQ_USED
186 int retry = 3;
187 int result; 187 int result;
188#endif
188 if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY) 189 if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY)
189 return -EINVAL; 190 return -EINVAL;
190 191
@@ -210,10 +211,12 @@ static int mag3110_read_data(short *x, short *y, short *z)
210 211
211 data->data_ready = 0; 212 data->data_ready = 0;
212 213
213 if (mag3110_read_block_data(data->client, 214 while (i2c_smbus_read_byte_data(data->client, MAG3110_DR_STATUS)) {
215 if (mag3110_read_block_data(data->client,
214 MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN, 216 MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN,
215 tmp_data) < 0) 217 tmp_data) < 0)
216 return -1; 218 return -1;
219 }
217 220
218 *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; 221 *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
219 *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; 222 *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
@@ -248,8 +251,26 @@ static void mag3110_dev_poll(struct input_polled_dev *dev)
248#if MAG3110_IRQ_USED 251#if MAG3110_IRQ_USED
249static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) 252static irqreturn_t mag3110_irq_handler(int irq, void *dev_id)
250{ 253{
254 int result;
255 u8 tmp_data[MAG3110_XYZ_DATA_LEN];
256 result = i2c_smbus_read_byte_data(mag3110_pdata->client,
257 MAG3110_DR_STATUS);
258 if (!(result & MAG3110_STATUS_ZYXDR))
259 return IRQ_NONE;
260
251 mag3110_pdata->data_ready = 1; 261 mag3110_pdata->data_ready = 1;
252 wake_up_interruptible(&mag3110_pdata->waitq); 262
263 if (mag3110_pdata->active == MAG_STANDBY)
264 /*
265 * Since the mode will be changed, sometimes irq will
266 * be handled in StandBy mode because of interrupt latency.
267 * So just clear the interrutp flag via reading block data.
268 */
269 mag3110_read_block_data(mag3110_pdata->client,
270 MAG3110_OUT_X_MSB,
271 MAG3110_XYZ_DATA_LEN, tmp_data);
272 else
273 wake_up_interruptible(&mag3110_pdata->waitq);
253 274
254 return IRQ_HANDLED; 275 return IRQ_HANDLED;
255} 276}
@@ -284,6 +305,7 @@ static ssize_t mag3110_enable_store(struct device *dev,
284 305
285 mutex_lock(&mag3110_lock); 306 mutex_lock(&mag3110_lock);
286 client = mag3110_pdata->client; 307 client = mag3110_pdata->client;
308
287 reg = mag3110_read_reg(client, MAG3110_CTRL_REG1); 309 reg = mag3110_read_reg(client, MAG3110_CTRL_REG1);
288 if (enable && mag3110_pdata->active == MAG_STANDBY) { 310 if (enable && mag3110_pdata->active == MAG_STANDBY) {
289 reg |= MAG3110_AC_MASK; 311 reg |= MAG3110_AC_MASK;
@@ -297,12 +319,10 @@ static ssize_t mag3110_enable_store(struct device *dev,
297 mag3110_pdata->active = MAG_STANDBY; 319 mag3110_pdata->active = MAG_STANDBY;
298 } 320 }
299 321
300 if (mag3110_pdata->active == MAG_ACTIVED) { 322 /* Read out MSB data to clear interrupt flag */
301 msleep(100); 323 msleep(100);
302 /* Read out MSB data to clear interrupt flag automatically */ 324 mag3110_read_block_data(mag3110_pdata->client, MAG3110_OUT_X_MSB,
303 mag3110_read_block_data(client, MAG3110_OUT_X_MSB,
304 MAG3110_XYZ_DATA_LEN, tmp_data); 325 MAG3110_XYZ_DATA_LEN, tmp_data);
305 }
306 mutex_unlock(&mag3110_lock); 326 mutex_unlock(&mag3110_lock);
307 return count; 327 return count;
308} 328}
@@ -402,6 +422,11 @@ static int mag3110_probe(struct i2c_client *client,
402 struct regulator *vdd, *vdd_io; 422 struct regulator *vdd, *vdd_io;
403 u32 pos = 0; 423 u32 pos = 0;
404 struct device_node *of_node = client->dev.of_node; 424 struct device_node *of_node = client->dev.of_node;
425#if MAG3110_IRQ_USED
426 struct irq_data *irq_data = irq_get_irq_data(client->irq);
427 u32 irq_flag;
428 bool shared_irq = of_property_read_bool(of_node, "shared-interrupt");
429#endif
405 vdd = NULL; 430 vdd = NULL;
406 vdd_io = NULL; 431 vdd_io = NULL;
407 432
@@ -484,10 +509,14 @@ static int mag3110_probe(struct i2c_client *client,
484 ret = -EINVAL; 509 ret = -EINVAL;
485 goto error_rm_poll_dev; 510 goto error_rm_poll_dev;
486 } 511 }
487 /* set irq type to edge rising */ 512
488#if MAG3110_IRQ_USED 513#if MAG3110_IRQ_USED
489 ret = request_irq(client->irq, mag3110_irq_handler, 514 irq_flag = irqd_get_trigger_type(irq_data);
490 IRQF_TRIGGER_RISING, client->dev.driver->name, idev); 515 irq_flag |= IRQF_ONESHOT;
516 if (shared_irq)
517 irq_flag |= IRQF_SHARED;
518 ret = request_threaded_irq(client->irq, NULL, mag3110_irq_handler,
519 irq_flag, client->dev.driver->name, idev);
491 if (ret < 0) { 520 if (ret < 0) {
492 dev_err(&client->dev, "failed to register irq %d!\n", 521 dev_err(&client->dev, "failed to register irq %d!\n",
493 client->irq); 522 client->irq);