Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: accel: Add driver for the MiraMEMS DA280 3-axis 14-bit digital accelerometer

Add an iio driver for the MiraMEMS DA280 3-axis 14-bit accelerometer, as
well as for the DA226 which is a fully compatible 2-axis version.

Datasheets for the DA280 and DA226 can be found at the manufacturers site:
http://www.miramems.com/en/products.asp?list=1

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Hans de Goede and committed by
Jonathan Cameron
f225951d a13e831f

+196
+2
Documentation/devicetree/bindings/i2c/trivial-devices.txt
··· 125 125 microchip,mcp4662-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) 126 126 microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) 127 127 microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) 128 + miramems,da226 MiraMEMS DA226 2-axis 14-bit digital accelerometer 129 + miramems,da280 MiraMEMS DA280 3-axis 14-bit digital accelerometer 128 130 miramems,da311 MiraMEMS DA311 3-axis 12-bit digital accelerometer 129 131 national,lm63 Temperature sensor with integrated fan control 130 132 national,lm75 I2C TEMP SENSOR
+10
drivers/iio/accel/Kconfig
··· 52 52 tristate 53 53 select REGMAP_SPI 54 54 55 + config DA280 56 + tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver" 57 + depends on I2C 58 + help 59 + Say yes here to build support for the MiraMEMS DA280 3-axis 14-bit 60 + digital accelerometer. 61 + 62 + To compile this driver as a module, choose M here: the 63 + module will be called da280. 64 + 55 65 config DA311 56 66 tristate "MiraMEMS DA311 3-axis 12-bit digital accelerometer driver" 57 67 depends on I2C
+1
drivers/iio/accel/Makefile
··· 8 8 obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o 9 9 obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o 10 10 obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o 11 + obj-$(CONFIG_DA280) += da280.o 11 12 obj-$(CONFIG_DA311) += da311.o 12 13 obj-$(CONFIG_DMARD06) += dmard06.o 13 14 obj-$(CONFIG_DMARD09) += dmard09.o
+183
drivers/iio/accel/da280.c
··· 1 + /** 2 + * IIO driver for the MiraMEMS DA280 3-axis accelerometer and 3 + * IIO driver for the MiraMEMS DA226 2-axis accelerometer 4 + * 5 + * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2, as published by the Free Software Foundation. 10 + */ 11 + 12 + #include <linux/module.h> 13 + #include <linux/i2c.h> 14 + #include <linux/iio/iio.h> 15 + #include <linux/iio/sysfs.h> 16 + #include <linux/byteorder/generic.h> 17 + 18 + #define DA280_REG_CHIP_ID 0x01 19 + #define DA280_REG_ACC_X_LSB 0x02 20 + #define DA280_REG_ACC_Y_LSB 0x04 21 + #define DA280_REG_ACC_Z_LSB 0x06 22 + #define DA280_REG_MODE_BW 0x11 23 + 24 + #define DA280_CHIP_ID 0x13 25 + #define DA280_MODE_ENABLE 0x1e 26 + #define DA280_MODE_DISABLE 0x9e 27 + 28 + enum { da226, da280 }; 29 + 30 + /* 31 + * a value of + or -4096 corresponds to + or - 1G 32 + * scale = 9.81 / 4096 = 0.002395019 33 + */ 34 + 35 + static const int da280_nscale = 2395019; 36 + 37 + #define DA280_CHANNEL(reg, axis) { \ 38 + .type = IIO_ACCEL, \ 39 + .address = reg, \ 40 + .modified = 1, \ 41 + .channel2 = IIO_MOD_##axis, \ 42 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 43 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 44 + } 45 + 46 + static const struct iio_chan_spec da280_channels[] = { 47 + DA280_CHANNEL(DA280_REG_ACC_X_LSB, X), 48 + DA280_CHANNEL(DA280_REG_ACC_Y_LSB, Y), 49 + DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z), 50 + }; 51 + 52 + struct da280_data { 53 + struct i2c_client *client; 54 + }; 55 + 56 + static int da280_enable(struct i2c_client *client, bool enable) 57 + { 58 + u8 data = enable ? DA280_MODE_ENABLE : DA280_MODE_DISABLE; 59 + 60 + return i2c_smbus_write_byte_data(client, DA280_REG_MODE_BW, data); 61 + } 62 + 63 + static int da280_read_raw(struct iio_dev *indio_dev, 64 + struct iio_chan_spec const *chan, 65 + int *val, int *val2, long mask) 66 + { 67 + struct da280_data *data = iio_priv(indio_dev); 68 + int ret; 69 + 70 + switch (mask) { 71 + case IIO_CHAN_INFO_RAW: 72 + ret = i2c_smbus_read_word_data(data->client, chan->address); 73 + if (ret < 0) 74 + return ret; 75 + /* 76 + * Values are 14 bits, stored as 16 bits with the 2 77 + * least significant bits always 0. 78 + */ 79 + *val = (short)ret >> 2; 80 + return IIO_VAL_INT; 81 + case IIO_CHAN_INFO_SCALE: 82 + *val = 0; 83 + *val2 = da280_nscale; 84 + return IIO_VAL_INT_PLUS_NANO; 85 + default: 86 + return -EINVAL; 87 + } 88 + } 89 + 90 + static const struct iio_info da280_info = { 91 + .driver_module = THIS_MODULE, 92 + .read_raw = da280_read_raw, 93 + }; 94 + 95 + static int da280_probe(struct i2c_client *client, 96 + const struct i2c_device_id *id) 97 + { 98 + int ret; 99 + struct iio_dev *indio_dev; 100 + struct da280_data *data; 101 + 102 + ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID); 103 + if (ret != DA280_CHIP_ID) 104 + return (ret < 0) ? ret : -ENODEV; 105 + 106 + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 107 + if (!indio_dev) 108 + return -ENOMEM; 109 + 110 + data = iio_priv(indio_dev); 111 + data->client = client; 112 + i2c_set_clientdata(client, indio_dev); 113 + 114 + indio_dev->dev.parent = &client->dev; 115 + indio_dev->info = &da280_info; 116 + indio_dev->modes = INDIO_DIRECT_MODE; 117 + indio_dev->channels = da280_channels; 118 + if (id->driver_data == da226) { 119 + indio_dev->name = "da226"; 120 + indio_dev->num_channels = 2; 121 + } else { 122 + indio_dev->name = "da280"; 123 + indio_dev->num_channels = 3; 124 + } 125 + 126 + ret = da280_enable(client, true); 127 + if (ret < 0) 128 + return ret; 129 + 130 + ret = iio_device_register(indio_dev); 131 + if (ret < 0) { 132 + dev_err(&client->dev, "device_register failed\n"); 133 + da280_enable(client, false); 134 + } 135 + 136 + return ret; 137 + } 138 + 139 + static int da280_remove(struct i2c_client *client) 140 + { 141 + struct iio_dev *indio_dev = i2c_get_clientdata(client); 142 + 143 + iio_device_unregister(indio_dev); 144 + 145 + return da280_enable(client, false); 146 + } 147 + 148 + #ifdef CONFIG_PM_SLEEP 149 + static int da280_suspend(struct device *dev) 150 + { 151 + return da280_enable(to_i2c_client(dev), false); 152 + } 153 + 154 + static int da280_resume(struct device *dev) 155 + { 156 + return da280_enable(to_i2c_client(dev), true); 157 + } 158 + #endif 159 + 160 + static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); 161 + 162 + static const struct i2c_device_id da280_i2c_id[] = { 163 + { "da226", da226 }, 164 + { "da280", da280 }, 165 + {} 166 + }; 167 + MODULE_DEVICE_TABLE(i2c, da280_i2c_id); 168 + 169 + static struct i2c_driver da280_driver = { 170 + .driver = { 171 + .name = "da280", 172 + .pm = &da280_pm_ops, 173 + }, 174 + .probe = da280_probe, 175 + .remove = da280_remove, 176 + .id_table = da280_i2c_id, 177 + }; 178 + 179 + module_i2c_driver(da280_driver); 180 + 181 + MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 182 + MODULE_DESCRIPTION("MiraMEMS DA280 3-Axis Accelerometer driver"); 183 + MODULE_LICENSE("GPL v2");