175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2b9d453a5SGwendal Grignou /* 3598893e9SHans de Goede * IIO driver for the MiraMEMS DA311 3-axis accelerometer 4598893e9SHans de Goede * 5598893e9SHans de Goede * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> 6598893e9SHans de Goede * Copyright (c) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. 7598893e9SHans de Goede */ 8598893e9SHans de Goede 9598893e9SHans de Goede #include <linux/module.h> 10598893e9SHans de Goede #include <linux/i2c.h> 11598893e9SHans de Goede #include <linux/iio/iio.h> 12598893e9SHans de Goede #include <linux/iio/sysfs.h> 13598893e9SHans de Goede #include <linux/byteorder/generic.h> 14598893e9SHans de Goede 15598893e9SHans de Goede #define DA311_CHIP_ID 0x13 16598893e9SHans de Goede 17598893e9SHans de Goede /* 18598893e9SHans de Goede * Note register addressed go from 0 - 0x3f and then wrap. 19598893e9SHans de Goede * For some reason there are 2 banks with 0 - 0x3f addresses, 20598893e9SHans de Goede * rather then a single 0-0x7f bank. 21598893e9SHans de Goede */ 22598893e9SHans de Goede 23598893e9SHans de Goede /* Bank 0 regs */ 24598893e9SHans de Goede #define DA311_REG_BANK 0x0000 25598893e9SHans de Goede #define DA311_REG_LDO_REG 0x0006 26598893e9SHans de Goede #define DA311_REG_CHIP_ID 0x000f 27598893e9SHans de Goede #define DA311_REG_TEMP_CFG_REG 0x001f 28598893e9SHans de Goede #define DA311_REG_CTRL_REG1 0x0020 29598893e9SHans de Goede #define DA311_REG_CTRL_REG3 0x0022 30598893e9SHans de Goede #define DA311_REG_CTRL_REG4 0x0023 31598893e9SHans de Goede #define DA311_REG_CTRL_REG5 0x0024 32598893e9SHans de Goede #define DA311_REG_CTRL_REG6 0x0025 33598893e9SHans de Goede #define DA311_REG_STATUS_REG 0x0027 34598893e9SHans de Goede #define DA311_REG_OUT_X_L 0x0028 35598893e9SHans de Goede #define DA311_REG_OUT_X_H 0x0029 36598893e9SHans de Goede #define DA311_REG_OUT_Y_L 0x002a 37598893e9SHans de Goede #define DA311_REG_OUT_Y_H 0x002b 38598893e9SHans de Goede #define DA311_REG_OUT_Z_L 0x002c 39598893e9SHans de Goede #define DA311_REG_OUT_Z_H 0x002d 40598893e9SHans de Goede #define DA311_REG_INT1_CFG 0x0030 41598893e9SHans de Goede #define DA311_REG_INT1_SRC 0x0031 42598893e9SHans de Goede #define DA311_REG_INT1_THS 0x0032 43598893e9SHans de Goede #define DA311_REG_INT1_DURATION 0x0033 44598893e9SHans de Goede #define DA311_REG_INT2_CFG 0x0034 45598893e9SHans de Goede #define DA311_REG_INT2_SRC 0x0035 46598893e9SHans de Goede #define DA311_REG_INT2_THS 0x0036 47598893e9SHans de Goede #define DA311_REG_INT2_DURATION 0x0037 48598893e9SHans de Goede #define DA311_REG_CLICK_CFG 0x0038 49598893e9SHans de Goede #define DA311_REG_CLICK_SRC 0x0039 50598893e9SHans de Goede #define DA311_REG_CLICK_THS 0x003a 51598893e9SHans de Goede #define DA311_REG_TIME_LIMIT 0x003b 52598893e9SHans de Goede #define DA311_REG_TIME_LATENCY 0x003c 53598893e9SHans de Goede #define DA311_REG_TIME_WINDOW 0x003d 54598893e9SHans de Goede 55598893e9SHans de Goede /* Bank 1 regs */ 56598893e9SHans de Goede #define DA311_REG_SOFT_RESET 0x0105 57598893e9SHans de Goede #define DA311_REG_OTP_XOFF_L 0x0110 58598893e9SHans de Goede #define DA311_REG_OTP_XOFF_H 0x0111 59598893e9SHans de Goede #define DA311_REG_OTP_YOFF_L 0x0112 60598893e9SHans de Goede #define DA311_REG_OTP_YOFF_H 0x0113 61598893e9SHans de Goede #define DA311_REG_OTP_ZOFF_L 0x0114 62598893e9SHans de Goede #define DA311_REG_OTP_ZOFF_H 0x0115 63598893e9SHans de Goede #define DA311_REG_OTP_XSO 0x0116 64598893e9SHans de Goede #define DA311_REG_OTP_YSO 0x0117 65598893e9SHans de Goede #define DA311_REG_OTP_ZSO 0x0118 66598893e9SHans de Goede #define DA311_REG_OTP_TRIM_OSC 0x011b 67598893e9SHans de Goede #define DA311_REG_LPF_ABSOLUTE 0x011c 68598893e9SHans de Goede #define DA311_REG_TEMP_OFF1 0x0127 69598893e9SHans de Goede #define DA311_REG_TEMP_OFF2 0x0128 70598893e9SHans de Goede #define DA311_REG_TEMP_OFF3 0x0129 71598893e9SHans de Goede #define DA311_REG_OTP_TRIM_THERM_H 0x011a 72598893e9SHans de Goede 73598893e9SHans de Goede /* 74598893e9SHans de Goede * a value of + or -1024 corresponds to + or - 1G 75598893e9SHans de Goede * scale = 9.81 / 1024 = 0.009580078 76598893e9SHans de Goede */ 77598893e9SHans de Goede 78598893e9SHans de Goede static const int da311_nscale = 9580078; 79598893e9SHans de Goede 80598893e9SHans de Goede #define DA311_CHANNEL(reg, axis) { \ 81598893e9SHans de Goede .type = IIO_ACCEL, \ 82598893e9SHans de Goede .address = reg, \ 83598893e9SHans de Goede .modified = 1, \ 84598893e9SHans de Goede .channel2 = IIO_MOD_##axis, \ 85598893e9SHans de Goede .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 86598893e9SHans de Goede .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 87598893e9SHans de Goede } 88598893e9SHans de Goede 89598893e9SHans de Goede static const struct iio_chan_spec da311_channels[] = { 90598893e9SHans de Goede /* | 0x80 comes from the android driver */ 91598893e9SHans de Goede DA311_CHANNEL(DA311_REG_OUT_X_L | 0x80, X), 92598893e9SHans de Goede DA311_CHANNEL(DA311_REG_OUT_Y_L | 0x80, Y), 93598893e9SHans de Goede DA311_CHANNEL(DA311_REG_OUT_Z_L | 0x80, Z), 94598893e9SHans de Goede }; 95598893e9SHans de Goede 96598893e9SHans de Goede struct da311_data { 97598893e9SHans de Goede struct i2c_client *client; 98598893e9SHans de Goede }; 99598893e9SHans de Goede 100598893e9SHans de Goede static int da311_register_mask_write(struct i2c_client *client, u16 addr, 101598893e9SHans de Goede u8 mask, u8 data) 102598893e9SHans de Goede { 103598893e9SHans de Goede int ret; 104598893e9SHans de Goede u8 tmp_data = 0; 105598893e9SHans de Goede 106598893e9SHans de Goede if (addr & 0xff00) { 107598893e9SHans de Goede /* Select bank 1 */ 108598893e9SHans de Goede ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, 0x01); 109598893e9SHans de Goede if (ret < 0) 110598893e9SHans de Goede return ret; 111598893e9SHans de Goede } 112598893e9SHans de Goede 113598893e9SHans de Goede if (mask != 0xff) { 114598893e9SHans de Goede ret = i2c_smbus_read_byte_data(client, addr); 115598893e9SHans de Goede if (ret < 0) 116598893e9SHans de Goede return ret; 117598893e9SHans de Goede tmp_data = ret; 118598893e9SHans de Goede } 119598893e9SHans de Goede 120598893e9SHans de Goede tmp_data &= ~mask; 121598893e9SHans de Goede tmp_data |= data & mask; 122598893e9SHans de Goede ret = i2c_smbus_write_byte_data(client, addr & 0xff, tmp_data); 123598893e9SHans de Goede if (ret < 0) 124598893e9SHans de Goede return ret; 125598893e9SHans de Goede 126598893e9SHans de Goede if (addr & 0xff00) { 127598893e9SHans de Goede /* Back to bank 0 */ 128598893e9SHans de Goede ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, 0x00); 129598893e9SHans de Goede if (ret < 0) 130598893e9SHans de Goede return ret; 131598893e9SHans de Goede } 132598893e9SHans de Goede 133598893e9SHans de Goede return 0; 134598893e9SHans de Goede } 135598893e9SHans de Goede 136598893e9SHans de Goede /* Init sequence taken from the android driver */ 137598893e9SHans de Goede static int da311_reset(struct i2c_client *client) 138598893e9SHans de Goede { 13972e36017SColin Ian King static const struct { 140598893e9SHans de Goede u16 addr; 141598893e9SHans de Goede u8 mask; 142598893e9SHans de Goede u8 data; 143598893e9SHans de Goede } init_data[] = { 144598893e9SHans de Goede { DA311_REG_TEMP_CFG_REG, 0xff, 0x08 }, 145598893e9SHans de Goede { DA311_REG_CTRL_REG5, 0xff, 0x80 }, 146598893e9SHans de Goede { DA311_REG_CTRL_REG4, 0x30, 0x00 }, 147598893e9SHans de Goede { DA311_REG_CTRL_REG1, 0xff, 0x6f }, 148598893e9SHans de Goede { DA311_REG_TEMP_CFG_REG, 0xff, 0x88 }, 149598893e9SHans de Goede { DA311_REG_LDO_REG, 0xff, 0x02 }, 150598893e9SHans de Goede { DA311_REG_OTP_TRIM_OSC, 0xff, 0x27 }, 151598893e9SHans de Goede { DA311_REG_LPF_ABSOLUTE, 0xff, 0x30 }, 152598893e9SHans de Goede { DA311_REG_TEMP_OFF1, 0xff, 0x3f }, 153598893e9SHans de Goede { DA311_REG_TEMP_OFF2, 0xff, 0xff }, 154598893e9SHans de Goede { DA311_REG_TEMP_OFF3, 0xff, 0x0f }, 155598893e9SHans de Goede }; 156598893e9SHans de Goede int i, ret; 157598893e9SHans de Goede 158598893e9SHans de Goede /* Reset */ 159598893e9SHans de Goede ret = da311_register_mask_write(client, DA311_REG_SOFT_RESET, 160598893e9SHans de Goede 0xff, 0xaa); 161598893e9SHans de Goede if (ret < 0) 162598893e9SHans de Goede return ret; 163598893e9SHans de Goede 164598893e9SHans de Goede for (i = 0; i < ARRAY_SIZE(init_data); i++) { 165598893e9SHans de Goede ret = da311_register_mask_write(client, 166598893e9SHans de Goede init_data[i].addr, 167598893e9SHans de Goede init_data[i].mask, 168598893e9SHans de Goede init_data[i].data); 169598893e9SHans de Goede if (ret < 0) 170598893e9SHans de Goede return ret; 171598893e9SHans de Goede } 172598893e9SHans de Goede 173598893e9SHans de Goede return 0; 174598893e9SHans de Goede } 175598893e9SHans de Goede 176598893e9SHans de Goede static int da311_enable(struct i2c_client *client, bool enable) 177598893e9SHans de Goede { 178598893e9SHans de Goede u8 data = enable ? 0x00 : 0x20; 179598893e9SHans de Goede 180598893e9SHans de Goede return da311_register_mask_write(client, DA311_REG_TEMP_CFG_REG, 181598893e9SHans de Goede 0x20, data); 182598893e9SHans de Goede } 183598893e9SHans de Goede 184598893e9SHans de Goede static int da311_read_raw(struct iio_dev *indio_dev, 185598893e9SHans de Goede struct iio_chan_spec const *chan, 186598893e9SHans de Goede int *val, int *val2, long mask) 187598893e9SHans de Goede { 188598893e9SHans de Goede struct da311_data *data = iio_priv(indio_dev); 189598893e9SHans de Goede int ret; 190598893e9SHans de Goede 191598893e9SHans de Goede switch (mask) { 192598893e9SHans de Goede case IIO_CHAN_INFO_RAW: 193598893e9SHans de Goede ret = i2c_smbus_read_word_data(data->client, chan->address); 194598893e9SHans de Goede if (ret < 0) 195598893e9SHans de Goede return ret; 196598893e9SHans de Goede /* 197598893e9SHans de Goede * Values are 12 bits, stored as 16 bits with the 4 198598893e9SHans de Goede * least significant bits always 0. 199598893e9SHans de Goede */ 200598893e9SHans de Goede *val = (short)ret >> 4; 201598893e9SHans de Goede return IIO_VAL_INT; 202598893e9SHans de Goede case IIO_CHAN_INFO_SCALE: 203598893e9SHans de Goede *val = 0; 204598893e9SHans de Goede *val2 = da311_nscale; 205598893e9SHans de Goede return IIO_VAL_INT_PLUS_NANO; 206598893e9SHans de Goede default: 207598893e9SHans de Goede return -EINVAL; 208598893e9SHans de Goede } 209598893e9SHans de Goede } 210598893e9SHans de Goede 211598893e9SHans de Goede static const struct iio_info da311_info = { 212598893e9SHans de Goede .read_raw = da311_read_raw, 213598893e9SHans de Goede }; 214598893e9SHans de Goede 215074e1ddbSAlexandru Ardelean static void da311_disable(void *client) 216074e1ddbSAlexandru Ardelean { 217074e1ddbSAlexandru Ardelean da311_enable(client, false); 218074e1ddbSAlexandru Ardelean } 219074e1ddbSAlexandru Ardelean 220a9e38f1eSUwe Kleine-König static int da311_probe(struct i2c_client *client) 221598893e9SHans de Goede { 222598893e9SHans de Goede int ret; 223598893e9SHans de Goede struct iio_dev *indio_dev; 224598893e9SHans de Goede struct da311_data *data; 225598893e9SHans de Goede 226598893e9SHans de Goede ret = i2c_smbus_read_byte_data(client, DA311_REG_CHIP_ID); 227598893e9SHans de Goede if (ret != DA311_CHIP_ID) 228598893e9SHans de Goede return (ret < 0) ? ret : -ENODEV; 229598893e9SHans de Goede 230598893e9SHans de Goede indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 231598893e9SHans de Goede if (!indio_dev) 232598893e9SHans de Goede return -ENOMEM; 233598893e9SHans de Goede 234598893e9SHans de Goede data = iio_priv(indio_dev); 235598893e9SHans de Goede data->client = client; 236598893e9SHans de Goede 237598893e9SHans de Goede indio_dev->info = &da311_info; 238598893e9SHans de Goede indio_dev->name = "da311"; 239598893e9SHans de Goede indio_dev->modes = INDIO_DIRECT_MODE; 240598893e9SHans de Goede indio_dev->channels = da311_channels; 241598893e9SHans de Goede indio_dev->num_channels = ARRAY_SIZE(da311_channels); 242598893e9SHans de Goede 243598893e9SHans de Goede ret = da311_reset(client); 244598893e9SHans de Goede if (ret < 0) 245598893e9SHans de Goede return ret; 246598893e9SHans de Goede 247598893e9SHans de Goede ret = da311_enable(client, true); 248598893e9SHans de Goede if (ret < 0) 249598893e9SHans de Goede return ret; 250598893e9SHans de Goede 251074e1ddbSAlexandru Ardelean ret = devm_add_action_or_reset(&client->dev, da311_disable, client); 252074e1ddbSAlexandru Ardelean if (ret) 253598893e9SHans de Goede return ret; 254598893e9SHans de Goede 255074e1ddbSAlexandru Ardelean return devm_iio_device_register(&client->dev, indio_dev); 256598893e9SHans de Goede } 257598893e9SHans de Goede 258598893e9SHans de Goede static int da311_suspend(struct device *dev) 259598893e9SHans de Goede { 260598893e9SHans de Goede return da311_enable(to_i2c_client(dev), false); 261598893e9SHans de Goede } 262598893e9SHans de Goede 263598893e9SHans de Goede static int da311_resume(struct device *dev) 264598893e9SHans de Goede { 265598893e9SHans de Goede return da311_enable(to_i2c_client(dev), true); 266598893e9SHans de Goede } 267598893e9SHans de Goede 2685d0e9e22SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); 269598893e9SHans de Goede 270598893e9SHans de Goede static const struct i2c_device_id da311_i2c_id[] = { 271598893e9SHans de Goede {"da311", 0}, 272598893e9SHans de Goede {} 273598893e9SHans de Goede }; 274598893e9SHans de Goede MODULE_DEVICE_TABLE(i2c, da311_i2c_id); 275598893e9SHans de Goede 276598893e9SHans de Goede static struct i2c_driver da311_driver = { 277598893e9SHans de Goede .driver = { 278598893e9SHans de Goede .name = "da311", 2795d0e9e22SJonathan Cameron .pm = pm_sleep_ptr(&da311_pm_ops), 280598893e9SHans de Goede }, 281*7cf15f42SUwe Kleine-König .probe = da311_probe, 282598893e9SHans de Goede .id_table = da311_i2c_id, 283598893e9SHans de Goede }; 284598893e9SHans de Goede 285598893e9SHans de Goede module_i2c_driver(da311_driver); 286598893e9SHans de Goede 287598893e9SHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 288598893e9SHans de Goede MODULE_DESCRIPTION("MiraMEMS DA311 3-Axis Accelerometer driver"); 289598893e9SHans de Goede MODULE_LICENSE("GPL v2"); 290