/*
* Freescale MMA9553L Intelligent Pedometer driver
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/pm_runtime.h>
#include "mma9551_core.h"
#define MMA9553_DRV_NAME "mma9553"
#define MMA9553_IRQ_NAME "mma9553_event"
#define MMA9553_GPIO_NAME "mma9553_int"
/* Pedometer configuration registers (R/W) */
#define MMA9553_REG_CONF_SLEEPMIN 0x00
#define MMA9553_REG_CONF_SLEEPMAX 0x02
#define MMA9553_REG_CONF_SLEEPTHD 0x04
#define MMA9553_MASK_CONF_WORD GENMASK(15, 0)
#define MMA9553_REG_CONF_CONF_STEPLEN 0x06
#define MMA9553_MASK_CONF_CONFIG BIT(15)
#define MMA9553_MASK_CONF_ACT_DBCNTM BIT(14)
#define MMA9553_MASK_CONF_SLP_DBCNTM BIT(13)
#define MMA9553_MASK_CONF_STEPLEN GENMASK(7, 0)
#define MMA9553_REG_CONF_HEIGHT_WEIGHT 0x08
#define MMA9553_MASK_CONF_HEIGHT GENMASK(15, 8)
#define MMA9553_MASK_CONF_WEIGHT GENMASK(7, 0)
#define MMA9553_REG_CONF_FILTER 0x0A
#define MMA9553_MASK_CONF_FILTSTEP GENMASK(15, 8)
#define MMA9553_MASK_CONF_MALE BIT(7)
#define MMA9553_MASK_CONF_FILTTIME GENMASK(6, 0)
#define MMA9553_REG_CONF_SPEED_STEP 0x0C
#define MMA9553_MASK_CONF_SPDPRD GENMASK(15, 8)
#define MMA9553_MASK_CONF_STEPCOALESCE GENMASK(7, 0)
#define MMA9553_REG_CONF_ACTTHD 0x0E
#define MMA9553_MAX_ACTTHD GENMASK(15, 0)
/* Pedometer status registers (R-only) */
#define MMA9553_REG_STATUS 0x00
#define MMA9553_MASK_STATUS_MRGFL BIT(15)
#define MMA9553_MASK_STATUS_SUSPCHG BIT(14)
#define MMA9553_MASK_STATUS_STEPCHG BIT(13)
#define MMA9553_MASK_STATUS_ACTCHG BIT(12)
#define MMA9553_MASK_STATUS_SUSP BIT(11)
#define MMA9553_MASK_STATUS_ACTIVITY GENMASK(10, 8)
#define MMA9553_MASK_STATUS_VERSION GENMASK(7, 0)
#define MMA9553_REG_STEPCNT 0x02
#define MMA9553_REG_DISTANCE 0x04
#define MMA9553_REG_SPEED 0x06
#define MMA9553_REG_CALORIES 0x08
#define MMA9553_REG_SLEEPCNT 0x0A
/* Pedometer events are always mapped to this pin. */
#define MMA9553_DEFAULT_GPIO_PIN mma9551_gpio6
#define MMA9553_DEFAULT_GPIO_POLARITY 0
/* Bitnum used for GPIO configuration = bit number in high status byte */
#define MMA9553_STATUS_TO_BITNUM(bit) (ffs(bit) - 9)
#define MMA9553_MAX_BITNUM MMA9553_STATUS_TO_BITNUM(BIT(16))
#define MMA9553_DEFAULT_SAMPLE_RATE 30 /* Hz */
/*
* The internal activity level must be stable for ACTTHD samples before
* ACTIVITY is updated. The ACTIVITY variable contains the current activity
* level and is updated every time a step is detected or once a second
* if there are no steps.
*/
#define MMA9553_ACTIVITY_THD_TO_SEC(thd) ((thd) / MMA9553_DEFAULT_SAMPLE_RATE)
#define MMA9553_ACTIVITY_SEC_TO_THD(sec) ((sec) * MMA9553_DEFAULT_SAMPLE_RATE)
/*
* Autonomously suspend pedometer if acceleration vector magnitude
* is near 1g (4096 at 0.244 mg/LSB resolution) for 30 seconds.
*/
#define MMA9553_DEFAULT_SLEEPMIN 3688 /* 0,9 g */
#define MMA9553_DEFAULT_SLEEPMAX 4508 /* 1,1 g */
#define MMA9553_DEFAULT_SLEEPTHD (MMA9553_DEFAULT_SAMPLE_RATE * 30)
#define MMA9553_CONFIG_RETRIES 2
/* Status register - activity field */
enum activity_level {
ACTIVITY_UNKNOWN,
ACTIVITY_REST,
ACTIVITY_WALKING,
ACTIVITY_JOGGING,
ACTIVITY_RUNNING,
};
static struct mma9553_event_info {
enum iio_chan_type type;
enum iio_modifier mod;
enum iio_event_direction dir;
} mma9553_events_info[] = {
{
.type = IIO_STEPS,
.mod = IIO_NO_MOD,
.dir = IIO_EV_DIR_NONE,
},
{
.type = IIO_ACTIVITY,
.mod = IIO_MOD_STILL,
.dir = IIO_EV_DIR_RISING,
},
{
.type = IIO_ACTIVITY,
.mod = IIO_MOD_STILL,
.dir = IIO_EV_DIR_FALLING,
},
{
.type = IIO_ACTIVITY,
.mod = IIO_MOD_WALKING,
.dir = IIO_EV_DIR_RISING,
},
{
.type = IIO_ACTIVITY,
.mod = IIO_MOD_WALKING,
.dir = IIO_EV_DIR_FALLING,
},