diff options
Diffstat (limited to 'drivers/iio/accel')
30 files changed, 1112 insertions, 361 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 15de262015df..c6d9517d7611 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -148,6 +148,17 @@ config HID_SENSOR_ACCEL_3D To compile this driver as a module, choose M here: the module will be called hid-sensor-accel-3d. +config IIO_CROS_EC_ACCEL_LEGACY + tristate "ChromeOS EC Legacy Accelerometer Sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select CROS_EC_LPC_REGISTER_DEVICE + help + Say yes here to get support for accelerometers on Chromebook using + legacy EC firmware. + Sensor data is retrieved through IO memory. + Newer devices should use IIO_CROS_EC_SENSORS. + config IIO_ST_ACCEL_3AXIS tristate "STMicroelectronics accelerometers 3-Axis Driver" depends on (I2C || SPI_MASTER) && SYSFS @@ -219,8 +230,8 @@ config KXCJK1013 select IIO_TRIGGERED_BUFFER help Say Y here if you want to build a driver for the Kionix KXCJK-1013 - triaxial acceleration sensor. This driver also supports KXCJ9-1008 - and KXTJ2-1009. + triaxial acceleration sensor. This driver also supports KXCJ9-1008, + KXTJ2-1009 and KXTF9. To compile this driver as a module, choose M here: the module will be called kxcjk-1013. diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 703e7c21f547..368aedb6377a 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -44,6 +44,8 @@ obj-$(CONFIG_SCA3000) += sca3000.o obj-$(CONFIG_STK8312) += stk8312.o obj-$(CONFIG_STK8BA50) += stk8ba50.o +obj-$(CONFIG_IIO_CROS_EC_ACCEL_LEGACY) += cros_ec_accel_legacy.o + obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 9ccb5828db98..7251d0e63d74 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -95,7 +95,6 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, } static const struct iio_info adxl345_info = { - .driver_module = THIS_MODULE, .read_raw = adxl345_read_raw, }; diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 3dec972ca672..cb9765a3de60 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -536,7 +536,6 @@ static const struct iio_info bma180_info = { .attrs = &bma180_attrs_group, .read_raw = bma180_read_raw, .write_raw = bma180_write_raw, - .driver_module = THIS_MODULE, }; static const char * const bma180_power_modes[] = { "low_noise", "low_power" }; @@ -700,7 +699,6 @@ static int bma180_trig_try_reen(struct iio_trigger *trig) static const struct iio_trigger_ops bma180_trigger_ops = { .set_trigger_state = bma180_data_rdy_trigger_set_state, .try_reenable = bma180_trig_try_reen, - .owner = THIS_MODULE, }; static int bma180_probe(struct i2c_client *client, diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 5099f295dd37..e25d91c017ed 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -186,7 +186,6 @@ static int bma220_write_raw(struct iio_dev *indio_dev, } static const struct iio_info bma220_info = { - .driver_module = THIS_MODULE, .read_raw = bma220_read_raw, .write_raw = bma220_write_raw, .attrs = &bma220_attribute_group, diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 807299dd45eb..870f92ef61c2 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -1094,7 +1094,6 @@ static const struct iio_info bmc150_accel_info = { .write_event_value = bmc150_accel_write_event, .write_event_config = bmc150_accel_write_event_config, .read_event_config = bmc150_accel_read_event_config, - .driver_module = THIS_MODULE, }; static const struct iio_info bmc150_accel_info_fifo = { @@ -1108,7 +1107,6 @@ static const struct iio_info bmc150_accel_info_fifo = { .validate_trigger = bmc150_accel_validate_trigger, .hwfifo_set_watermark = bmc150_accel_set_watermark, .hwfifo_flush_to_buffer = bmc150_accel_fifo_flush, - .driver_module = THIS_MODULE, }; static const unsigned long bmc150_accel_scan_masks[] = { @@ -1200,7 +1198,6 @@ static int bmc150_accel_trigger_set_state(struct iio_trigger *trig, static const struct iio_trigger_ops bmc150_accel_trigger_ops = { .set_trigger_state = bmc150_accel_trigger_set_state, .try_reenable = bmc150_accel_trig_try_reen, - .owner = THIS_MODULE, }; static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c new file mode 100644 index 000000000000..063e89eff791 --- /dev/null +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -0,0 +1,423 @@ +/* + * Driver for older Chrome OS EC accelerometer + * + * Copyright 2017 Google, Inc + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that 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. + * + * This driver uses the memory mapper cros-ec interface to communicate + * with the Chrome OS EC about accelerometer data. + * Accelerometer access is presented through iio sysfs. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/kfifo_buf.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/kernel.h> +#include <linux/mfd/cros_ec.h> +#include <linux/mfd/cros_ec_commands.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/platform_device.h> + +#define DRV_NAME "cros-ec-accel-legacy" + +/* + * Sensor scale hard coded at 10 bits per g, computed as: + * g / (2^10 - 1) = 0.009586168; with g = 9.80665 m.s^-2 + */ +#define ACCEL_LEGACY_NSCALE 9586168 + +/* Indices for EC sensor values. */ +enum { + X, + Y, + Z, + MAX_AXIS, +}; + +/* State data for cros_ec_accel_legacy iio driver. */ +struct cros_ec_accel_legacy_state { + struct cros_ec_device *ec; + + /* + * Array holding data from a single capture. 2 bytes per channel + * for the 3 channels plus the timestamp which is always last and + * 8-bytes aligned. + */ + s16 capture_data[8]; + s8 sign[MAX_AXIS]; + u8 sensor_num; +}; + +static int ec_cmd_read_u8(struct cros_ec_device *ec, unsigned int offset, + u8 *dest) +{ + return ec->cmd_readmem(ec, offset, 1, dest); +} + +static int ec_cmd_read_u16(struct cros_ec_device *ec, unsigned int offset, + u16 *dest) +{ + __le16 tmp; + int ret = ec->cmd_readmem(ec, offset, 2, &tmp); + + *dest = le16_to_cpu(tmp); + + return ret; +} + +/** + * read_ec_until_not_busy() - Read from EC status byte until it reads not busy. + * @st: Pointer to state information for device. + * + * This function reads EC status until its busy bit gets cleared. It does not + * wait indefinitely and returns -EIO if the EC status is still busy after a + * few hundreds milliseconds. + * + * Return: 8-bit status if ok, -EIO on error + */ +static int read_ec_until_not_busy(struct cros_ec_accel_legacy_state *st) +{ + struct cros_ec_device *ec = st->ec; + u8 status; + int attempts = 0; + + ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status); + while (status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) { + /* Give up after enough attempts, return error. */ + if (attempts++ >= 50) + return -EIO; + + /* Small delay every so often. */ + if (attempts % 5 == 0) + msleep(25); + + ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status); + } + + return status; +} + +/** + * read_ec_accel_data_unsafe() - Read acceleration data from EC shared memory. + * @st: Pointer to state information for device. + * @scan_mask: Bitmap of the sensor indices to scan. + * @data: Location to store data. + * + * This is the unsafe function for reading the EC data. It does not guarantee + * that the EC will not modify the data as it is being read in. + */ +static void read_ec_accel_data_unsafe(struct cros_ec_accel_legacy_state *st, + unsigned long scan_mask, s16 *data) +{ + int i = 0; + int num_enabled = bitmap_weight(&scan_mask, MAX_AXIS); + + /* Read all sensors enabled in scan_mask. Each value is 2 bytes. */ + while (num_enabled--) { + i = find_next_bit(&scan_mask, MAX_AXIS, i); + ec_cmd_read_u16(st->ec, + EC_MEMMAP_ACC_DATA + + sizeof(s16) * + (1 + i + st->sensor_num * MAX_AXIS), + data); + *data *= st->sign[i]; + i++; + data++; + } +} + +/** + * read_ec_accel_data() - Read acceleration data from EC shared memory. + * @st: Pointer to state information for device. + * @scan_mask: Bitmap of the sensor indices to scan. + * @data: Location to store data. + * + * This is the safe function for reading the EC data. It guarantees that + * the data sampled was not modified by the EC while being read. + * + * Return: 0 if ok, -ve on error + */ +static int read_ec_accel_data(struct cros_ec_accel_legacy_state *st, + unsigned long scan_mask, s16 *data) +{ + u8 samp_id = 0xff; + u8 status = 0; + int ret; + int attempts = 0; + + /* + * Continually read all data from EC until the status byte after + * all reads reflects that the EC is not busy and the sample id + * matches the sample id from before all reads. This guarantees + * that data read in was not modified by the EC while reading. + */ + while ((status & (EC_MEMMAP_ACC_STATUS_BUSY_BIT | + EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK)) != samp_id) { + /* If we have tried to read too many times, return error. */ + if (attempts++ >= 5) + return -EIO; + + /* Read status byte until EC is not busy. */ + ret = read_ec_until_not_busy(st); + if (ret < 0) + return ret; + status = ret; + + /* + * Store the current sample id so that we can compare to the + * sample id after reading the data. + */ + samp_id = status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; + + /* Read all EC data, format it, and store it into data. */ + read_ec_accel_data_unsafe(st, scan_mask, data); + + /* Read status byte. */ + ec_cmd_read_u8(st->ec, EC_MEMMAP_ACC_STATUS, &status); + } + + return 0; +} + +static int cros_ec_accel_legacy_read(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); + s16 data = 0; + int ret = IIO_VAL_INT; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = read_ec_accel_data(st, (1 << chan->scan_index), &data); + if (ret) + return ret; + *val = data; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = ACCEL_LEGACY_NSCALE; + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_CALIBBIAS: + /* Calibration not supported. */ + *val = 0; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int cros_ec_accel_legacy_write(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + /* + * Do nothing but don't return an error code to allow calibration + * script to work. + */ + if (mask == IIO_CHAN_INFO_CALIBBIAS) + return 0; + + return -EINVAL; +} + +static const struct iio_info cros_ec_accel_legacy_info = { + .read_raw = &cros_ec_accel_legacy_read, + .write_raw = &cros_ec_accel_legacy_write, +}; + +/** + * cros_ec_accel_legacy_capture() - The trigger handler function + * @irq: The interrupt number. + * @p: Private data - always a pointer to the poll func. + * + * On a trigger event occurring, if the pollfunc is attached then this + * handler is called as a threaded interrupt (and hence may sleep). It + * is responsible for grabbing data from the device and pushing it into + * the associated buffer. + * + * Return: IRQ_HANDLED + */ +static irqreturn_t cros_ec_accel_legacy_capture(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); + + /* Clear capture data. */ + memset(st->capture_data, 0, sizeof(st->capture_data)); + + /* + * Read data based on which channels are enabled in scan mask. Note + * that on a capture we are always reading the calibrated data. + */ + read_ec_accel_data(st, *indio_dev->active_scan_mask, st->capture_data); + + iio_push_to_buffers_with_timestamp(indio_dev, (void *)st->capture_data, + iio_get_time_ns(indio_dev)); + + /* + * Tell the core we are done with this trigger and ready for the + * next one. + */ + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static char *cros_ec_accel_legacy_loc_strings[] = { + [MOTIONSENSE_LOC_BASE] = "base", + [MOTIONSENSE_LOC_LID] = "lid", + [MOTIONSENSE_LOC_MAX] = "unknown", +}; + +static ssize_t cros_ec_accel_legacy_loc(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%s\n", + cros_ec_accel_legacy_loc_strings[st->sensor_num + + MOTIONSENSE_LOC_BASE]); +} + +static ssize_t cros_ec_accel_legacy_id(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", st->sensor_num); +} + +static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = { + { + .name = "id", + .shared = IIO_SHARED_BY_ALL, + .read = cros_ec_accel_legacy_id, + }, + { + .name = "location", + .shared = IIO_SHARED_BY_ALL, + .read = cros_ec_accel_legacy_loc, + }, + { } +}; + +#define CROS_EC_ACCEL_LEGACY_CHAN(_axis) \ + { \ + .type = IIO_ACCEL, \ + .channel2 = IIO_MOD_X + (_axis), \ + .modified = 1, \ + .info_mask_separate = \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = cros_ec_accel_legacy_ext_info, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + }, \ + } \ + +static struct iio_chan_spec ec_accel_channels[] = { + CROS_EC_ACCEL_LEGACY_CHAN(X), + CROS_EC_ACCEL_LEGACY_CHAN(Y), + CROS_EC_ACCEL_LEGACY_CHAN(Z), + IIO_CHAN_SOFT_TIMESTAMP(MAX_AXIS) +}; + +static int cros_ec_accel_legacy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cros_ec_dev *ec = dev_get_drvdata(dev->parent); + struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); + struct iio_dev *indio_dev; + struct cros_ec_accel_legacy_state *state; + int ret, i; + + if (!ec || !ec->ec_dev) { + dev_warn(&pdev->dev, "No EC device found.\n"); + return -EINVAL; + } + + if (!ec->ec_dev->cmd_readmem) { + dev_warn(&pdev->dev, "EC does not support direct reads.\n"); + return -EINVAL; + } + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + state = iio_priv(indio_dev); + state->ec = ec->ec_dev; + state->sensor_num = sensor_platform->sensor_num; + + indio_dev->dev.parent = dev; + indio_dev->name = pdev->name; + indio_dev->channels = ec_accel_channels; + /* + * Present the channel using HTML5 standard: + * need to invert X and Y and invert some lid axis. + */ + for (i = X ; i < MAX_AXIS; i++) { + switch (i) { + case X: + ec_accel_channels[X].scan_index = Y; + case Y: + ec_accel_channels[Y].scan_index = X; + case Z: + ec_accel_channels[Z].scan_index = Z; + } + if (state->sensor_num == MOTIONSENSE_LOC_LID && i != Y) + state->sign[i] = -1; + else + state->sign[i] = 1; + } + indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &cros_ec_accel_legacy_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + cros_ec_accel_legacy_capture, + NULL); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static struct platform_driver cros_ec_accel_platform_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = cros_ec_accel_legacy_probe, +}; +module_platform_driver(cros_ec_accel_platform_driver); + +MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver"); +MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c index ed8343aeac9c..6c214783241c 100644 --- a/drivers/iio/accel/da280.c +++ b/drivers/iio/accel/da280.c @@ -88,7 +88,6 @@ static int da280_read_raw(struct iio_dev *indio_dev, } static const struct iio_info da280_info = { - .driver_module = THIS_MODULE, .read_raw = da280_read_raw, }; diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c index c0c1620d2a2f..aa64bca00955 100644 --- a/drivers/iio/accel/da311.c +++ b/drivers/iio/accel/da311.c @@ -212,7 +212,6 @@ static int da311_read_raw(struct iio_dev *indio_dev, } static const struct iio_info da311_info = { - .driver_module = THIS_MODULE, .read_raw = da311_read_raw, }; diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index 656ca8e1927f..d87e2c751475 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -124,7 +124,6 @@ static int dmard06_read_raw(struct iio_dev *indio_dev, } static const struct iio_info dmard06_info = { - .driver_module = THIS_MODULE, .read_raw = dmard06_read_raw, }; diff --git a/drivers/iio/accel/dmard09.c b/drivers/iio/accel/dmard09.c index d3a28f96565c..16a7e74f5e9a 100644 --- a/drivers/iio/accel/dmard09.c +++ b/drivers/iio/accel/dmard09.c @@ -93,7 +93,6 @@ static int dmard09_read_raw(struct iio_dev *indio_dev, } static const struct iio_info dmard09_info = { - .driver_module = THIS_MODULE, .read_raw = dmard09_read_raw, }; diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c index b8736cc75656..9518ea00167e 100644 --- a/drivers/iio/accel/dmard10.c +++ b/drivers/iio/accel/dmard10.c @@ -170,7 +170,6 @@ static int dmard10_read_raw(struct iio_dev *indio_dev, } static const struct iio_info dmard10_info = { - .driver_module = THIS_MODULE, .read_raw = dmard10_read_raw, }; diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 2238a26aba63..c066a3bdbff7 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -225,7 +225,6 @@ static int accel_3d_write_raw(struct iio_dev *indio_dev, } static const struct iio_info accel_3d_info = { - .driver_module = THIS_MODULE, .read_raw = &accel_3d_read_raw, .write_raw = &accel_3d_write_raw, }; diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 3f968c46e667..af53a1084ee5 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -34,6 +34,13 @@ #define KXCJK1013_DRV_NAME "kxcjk1013" #define KXCJK1013_IRQ_NAME "kxcjk1013_event" +#define KXTF9_REG_HP_XOUT_L 0x00 +#define KXTF9_REG_HP_XOUT_H 0x01 +#define KXTF9_REG_HP_YOUT_L 0x02 +#define KXTF9_REG_HP_YOUT_H 0x03 +#define KXTF9_REG_HP_ZOUT_L 0x04 +#define KXTF9_REG_HP_ZOUT_H 0x05 + #define KXCJK1013_REG_XOUT_L 0x06 /* * From low byte X axis register, all the other addresses of Y and Z can be @@ -48,17 +55,33 @@ #define KXCJK1013_REG_DCST_RESP 0x0C #define KXCJK1013_REG_WHO_AM_I 0x0F -#define KXCJK1013_REG_INT_SRC1 0x16 +#define KXTF9_REG_TILT_POS_CUR 0x10 +#define KXTF9_REG_TILT_POS_PREV 0x11 +#define KXTF9_REG_INT_SRC1 0x15 +#define KXCJK1013_REG_INT_SRC1 0x16 /* compatible, but called INT_SRC2 in KXTF9 ds */ #define KXCJK1013_REG_INT_SRC2 0x17 #define KXCJK1013_REG_STATUS_REG 0x18 #define KXCJK1013_REG_INT_REL 0x1A #define KXCJK1013_REG_CTRL1 0x1B -#define KXCJK1013_REG_CTRL2 0x1D +#define KXTF9_REG_CTRL2 0x1C +#define KXCJK1013_REG_CTRL2 0x1D /* mostly compatible, CTRL_REG3 in KTXF9 ds */ #define KXCJK1013_REG_INT_CTRL1 0x1E #define KXCJK1013_REG_INT_CTRL2 0x1F +#define KXTF9_REG_INT_CTRL3 0x20 #define KXCJK1013_REG_DATA_CTRL 0x21 +#define KXTF9_REG_TILT_TIMER 0x28 #define KXCJK1013_REG_WAKE_TIMER 0x29 +#define KXTF9_REG_TDT_TIMER 0x2B +#define KXTF9_REG_TDT_THRESH_H 0x2C +#define KXTF9_REG_TDT_THRESH_L 0x2D +#define KXTF9_REG_TDT_TAP_TIMER 0x2E +#define KXTF9_REG_TDT_TOTAL_TIMER 0x2F +#define KXTF9_REG_TDT_LATENCY_TIMER 0x30 +#define KXTF9_REG_TDT_WINDOW_TIMER 0x31 #define KXCJK1013_REG_SELF_TEST 0x3A +#define KXTF9_REG_WAKE_THRESH 0x5A +#define KXTF9_REG_TILT_ANGLE 0x5C +#define KXTF9_REG_HYST_SET 0x5F #define KXCJK1013_REG_WAKE_THRES 0x6A #define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7) @@ -67,14 +90,33 @@ #define KXCJK1013_REG_CTRL1_BIT_GSEL1 BIT(4) #define KXCJK1013_REG_CTRL1_BIT_GSEL0 BIT(3) #define KXCJK1013_REG_CTRL1_BIT_WUFE BIT(1) -#define KXCJK1013_REG_INT_REG1_BIT_IEA BIT(4) -#define KXCJK1013_REG_INT_REG1_BIT_IEN BIT(5) + +#define KXCJK1013_REG_INT_CTRL1_BIT_IEU BIT(2) /* KXTF9 */ +#define KXCJK1013_REG_INT_CTRL1_BIT_IEL BIT(3) +#define KXCJK1013_REG_INT_CTRL1_BIT_IEA BIT(4) +#define KXCJK1013_REG_INT_CTRL1_BIT_IEN BIT(5) + +#define KXTF9_REG_TILT_BIT_LEFT_EDGE BIT(5) +#define KXTF9_REG_TILT_BIT_RIGHT_EDGE BIT(4) +#define KXTF9_REG_TILT_BIT_LOWER_EDGE BIT(3) +#define KXTF9_REG_TILT_BIT_UPPER_EDGE BIT(2) +#define KXTF9_REG_TILT_BIT_FACE_DOWN BIT(1) +#define KXTF9_REG_TILT_BIT_FACE_UP BIT(0) #define KXCJK1013_DATA_MASK_12_BIT 0x0FFF #define KXCJK1013_MAX_STARTUP_TIME_US 100000 #define KXCJK1013_SLEEP_DELAY_MS 2000 +#define KXCJK1013_REG_INT_SRC1_BIT_TPS BIT(0) /* KXTF9 */ +#define KXCJK1013_REG_INT_SRC1_BIT_WUFS BIT(1) +#define KXCJK1013_REG_INT_SRC1_MASK_TDTS (BIT(2) | BIT(3)) /* KXTF9 */ +#define KXCJK1013_REG_INT_SRC1_TAP_NONE 0 +#define KXCJK1013_REG_INT_SRC1_TAP_SINGLE BIT(2) +#define KXCJK1013_REG_INT_SRC1_TAP_DOUBLE BIT(3) +#define KXCJK1013_REG_INT_SRC1_BIT_DRDY BIT(4) + +/* KXCJK: INT_SOURCE2: motion detect, KXTF9: INT_SRC_REG1: tap detect */ #define KXCJK1013_REG_INT_SRC2_BIT_ZP BIT(0) #define KXCJK1013_REG_INT_SRC2_BIT_ZN BIT(1) #define KXCJK1013_REG_INT_SRC2_BIT_YP BIT(2) @@ -88,6 +130,7 @@ enum kx_chipset { KXCJK1013, KXCJ91008, KXTJ21009, + KXTF9, KX_MAX_CHIPS /* this must be last */ }; @@ -128,15 +171,42 @@ enum kxcjk1013_range { KXCJK1013_RANGE_8G, }; -static const struct { +struct kx_odr_map { int val; int val2; int odr_bits; -} samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09}, - {3, 125000, 0x0A}, {6, 250000, 0x0B}, {12, 500000, 0}, - {25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03}, - {200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06}, - {1600, 0, 0x07} }; + int wuf_bits; +}; + +static const struct kx_odr_map samp_freq_table[] = { + { 0, 781000, 0x08, 0x00 }, + { 1, 563000, 0x09, 0x01 }, + { 3, 125000, 0x0A, 0x02 }, + { 6, 250000, 0x0B, 0x03 }, + { 12, 500000, 0x00, 0x04 }, + { 25, 0, 0x01, 0x05 }, + { 50, 0, 0x02, 0x06 }, + { 100, 0, 0x03, 0x06 }, + { 200, 0, 0x04, 0x06 }, + { 400, 0, 0x05, 0x06 }, + { 800, 0, 0x06, 0x06 }, + { 1600, 0, 0x07, 0x06 }, +}; + +static const char *const kxcjk1013_samp_freq_avail = + "0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600"; + +static const struct kx_odr_map kxtf9_samp_freq_table[] = { + { 25, 0, 0x01, 0x00 }, + { 50, 0, 0x02, 0x01 }, + { 100, 0, 0x03, 0x01 }, + { 200, 0, 0x04, 0x01 }, + { 400, 0, 0x05, 0x01 }, + { 800, 0, 0x06, 0x01 }, +}; + +static const char *const kxtf9_samp_freq_avail = + "25 50 100 200 400 800"; /* Refer to section 4 of the specification */ static const struct { @@ -188,6 +258,15 @@ static const struct { {0x06, 3000}, {0x07, 2000}, }, + /* KXTF9 */ + { + {0x01, 81000}, + {0x02, 41000}, + {0x03, 21000}, + {0x04, 11000}, + {0x05, 5100}, + {0x06, 2700}, + }, }; static const struct { @@ -198,23 +277,6 @@ static const struct { {19163, 1, 0}, {38326, 0, 1} }; -static const struct { - int val; - int val2; - int odr_bits; -} wake_odr_data_rate_table[] = { {0, 781000, 0x00}, - {1, 563000, 0x01}, - {3, 125000, 0x02}, - {6, 250000, 0x03}, - {12, 500000, 0x04}, - {25, 0, 0x05}, - {50, 0, 0x06}, - {100, 0, 0x06}, - {200, 0, 0x06}, - {400, 0, 0x06}, - {800, 0, 0x06}, - {1600, 0, 0x06} }; - static int kxcjk1013_set_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode mode) { @@ -341,9 +403,9 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) |