|
@@ -48,6 +48,13 @@
|
|
|
|
|
|
#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
|
|
#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
|
|
|
|
|
|
|
|
+#define SELFTEST_OK 0
|
|
|
|
+#define SELFTEST_FAIL -1
|
|
|
|
+#define SELFTEST_IRQ -2
|
|
|
|
+
|
|
|
|
+#define IRQ_LINE0 0
|
|
|
|
+#define IRQ_LINE1 1
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* The sensor can also generate interrupts (DRDY) but it's pretty pointless
|
|
* The sensor can also generate interrupts (DRDY) but it's pretty pointless
|
|
* because they are generated even if the data do not change. So it's better
|
|
* because they are generated even if the data do not change. So it's better
|
|
@@ -226,8 +233,25 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
|
|
s16 x, y, z;
|
|
s16 x, y, z;
|
|
u8 selftest;
|
|
u8 selftest;
|
|
int ret;
|
|
int ret;
|
|
|
|
+ u8 ctrl_reg_data;
|
|
|
|
+ unsigned char irq_cfg;
|
|
|
|
|
|
mutex_lock(&lis3->mutex);
|
|
mutex_lock(&lis3->mutex);
|
|
|
|
+
|
|
|
|
+ irq_cfg = lis3->irq_cfg;
|
|
|
|
+ if (lis3_dev.whoami == WAI_8B) {
|
|
|
|
+ lis3->data_ready_count[IRQ_LINE0] = 0;
|
|
|
|
+ lis3->data_ready_count[IRQ_LINE1] = 0;
|
|
|
|
+
|
|
|
|
+ /* Change interrupt cfg to data ready for selftest */
|
|
|
|
+ atomic_inc(&lis3_dev.wake_thread);
|
|
|
|
+ lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
|
|
|
|
+ lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
|
|
|
|
+ lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
|
|
|
|
+ ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
|
|
|
|
+ (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
|
|
|
|
+ }
|
|
|
|
+
|
|
if (lis3_dev.whoami == WAI_3DC) {
|
|
if (lis3_dev.whoami == WAI_3DC) {
|
|
ctlreg = CTRL_REG4;
|
|
ctlreg = CTRL_REG4;
|
|
selftest = CTRL4_ST0;
|
|
selftest = CTRL4_ST0;
|
|
@@ -257,13 +281,33 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
|
|
results[2] = z - lis3->read_data(lis3, OUTZ);
|
|
results[2] = z - lis3->read_data(lis3, OUTZ);
|
|
|
|
|
|
ret = 0;
|
|
ret = 0;
|
|
|
|
+
|
|
|
|
+ if (lis3_dev.whoami == WAI_8B) {
|
|
|
|
+ /* Restore original interrupt configuration */
|
|
|
|
+ atomic_dec(&lis3_dev.wake_thread);
|
|
|
|
+ lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
|
|
|
|
+ lis3->irq_cfg = irq_cfg;
|
|
|
|
+
|
|
|
|
+ if ((irq_cfg & LIS3_IRQ1_MASK) &&
|
|
|
|
+ lis3->data_ready_count[IRQ_LINE0] < 2) {
|
|
|
|
+ ret = SELFTEST_IRQ;
|
|
|
|
+ goto fail;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ((irq_cfg & LIS3_IRQ2_MASK) &&
|
|
|
|
+ lis3->data_ready_count[IRQ_LINE1] < 2) {
|
|
|
|
+ ret = SELFTEST_IRQ;
|
|
|
|
+ goto fail;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
if (lis3->pdata) {
|
|
if (lis3->pdata) {
|
|
int i;
|
|
int i;
|
|
for (i = 0; i < 3; i++) {
|
|
for (i = 0; i < 3; i++) {
|
|
/* Check against selftest acceptance limits */
|
|
/* Check against selftest acceptance limits */
|
|
if ((results[i] < lis3->pdata->st_min_limits[i]) ||
|
|
if ((results[i] < lis3->pdata->st_min_limits[i]) ||
|
|
(results[i] > lis3->pdata->st_max_limits[i])) {
|
|
(results[i] > lis3->pdata->st_max_limits[i])) {
|
|
- ret = -EIO;
|
|
|
|
|
|
+ ret = SELFTEST_FAIL;
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -426,13 +470,24 @@ static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
|
|
mutex_unlock(&lis3->mutex);
|
|
mutex_unlock(&lis3->mutex);
|
|
}
|
|
}
|
|
|
|
|
|
-static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
|
|
|
|
|
|
+static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
|
|
{
|
|
{
|
|
|
|
+ int dummy;
|
|
|
|
+
|
|
|
|
+ /* Dummy read to ack interrupt */
|
|
|
|
+ lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
|
|
|
|
+ lis3->data_ready_count[index]++;
|
|
|
|
+}
|
|
|
|
|
|
|
|
+static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
|
|
|
|
+{
|
|
struct lis3lv02d *lis3 = data;
|
|
struct lis3lv02d *lis3 = data;
|
|
|
|
+ u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
|
|
|
|
|
|
- if ((lis3->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
|
|
|
|
|
|
+ if (irq_cfg == LIS3_IRQ1_CLICK)
|
|
lis302dl_interrupt_handle_click(lis3);
|
|
lis302dl_interrupt_handle_click(lis3);
|
|
|
|
+ else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
|
|
|
|
+ lis302dl_data_ready(lis3, IRQ_LINE0);
|
|
else
|
|
else
|
|
lis3lv02d_joystick_poll(lis3->idev);
|
|
lis3lv02d_joystick_poll(lis3->idev);
|
|
|
|
|
|
@@ -441,11 +496,13 @@ static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
|
|
|
|
|
|
static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
|
|
static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
|
|
{
|
|
{
|
|
-
|
|
|
|
struct lis3lv02d *lis3 = data;
|
|
struct lis3lv02d *lis3 = data;
|
|
|
|
+ u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
|
|
|
|
|
|
- if ((lis3->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
|
|
|
|
|
|
+ if (irq_cfg == LIS3_IRQ2_CLICK)
|
|
lis302dl_interrupt_handle_click(lis3);
|
|
lis302dl_interrupt_handle_click(lis3);
|
|
|
|
+ else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
|
|
|
|
+ lis302dl_data_ready(lis3, IRQ_LINE1);
|
|
else
|
|
else
|
|
lis3lv02d_joystick_poll(lis3->idev);
|
|
lis3lv02d_joystick_poll(lis3->idev);
|
|
|
|
|
|
@@ -648,12 +705,27 @@ static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
|
|
static ssize_t lis3lv02d_selftest_show(struct device *dev,
|
|
static ssize_t lis3lv02d_selftest_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
{
|
|
- int result;
|
|
|
|
s16 values[3];
|
|
s16 values[3];
|
|
|
|
|
|
|
|
+ static const char ok[] = "OK";
|
|
|
|
+ static const char fail[] = "FAIL";
|
|
|
|
+ static const char irq[] = "FAIL_IRQ";
|
|
|
|
+ const char *res;
|
|
|
|
+
|
|
lis3lv02d_sysfs_poweron(&lis3_dev);
|
|
lis3lv02d_sysfs_poweron(&lis3_dev);
|
|
- result = lis3lv02d_selftest(&lis3_dev, values);
|
|
|
|
- return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL",
|
|
|
|
|
|
+ switch (lis3lv02d_selftest(&lis3_dev, values)) {
|
|
|
|
+ case SELFTEST_FAIL:
|
|
|
|
+ res = fail;
|
|
|
|
+ break;
|
|
|
|
+ case SELFTEST_IRQ:
|
|
|
|
+ res = irq;
|
|
|
|
+ break;
|
|
|
|
+ case SELFTEST_OK:
|
|
|
|
+ default:
|
|
|
|
+ res = ok;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return sprintf(buf, "%s %d %d %d\n", res,
|
|
values[0], values[1], values[2]);
|
|
values[0], values[1], values[2]);
|
|
}
|
|
}
|
|
|
|
|