175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2b9d453a5SGwendal Grignou /* 3569906e2SHans de Goede * IIO driver for the 3-axis accelerometer Domintech ARD10. 4569906e2SHans de Goede * 5569906e2SHans de Goede * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> 6569906e2SHans de Goede * Copyright (c) 2012 Domintech Technology Co., Ltd 7569906e2SHans de Goede */ 8569906e2SHans de Goede 9569906e2SHans de Goede #include <linux/module.h> 10569906e2SHans de Goede #include <linux/i2c.h> 11569906e2SHans de Goede #include <linux/iio/iio.h> 12569906e2SHans de Goede #include <linux/iio/sysfs.h> 13569906e2SHans de Goede #include <linux/byteorder/generic.h> 14569906e2SHans de Goede 15569906e2SHans de Goede #define DMARD10_REG_ACTR 0x00 16569906e2SHans de Goede #define DMARD10_REG_AFEM 0x0c 17569906e2SHans de Goede #define DMARD10_REG_STADR 0x12 18569906e2SHans de Goede #define DMARD10_REG_STAINT 0x1c 19569906e2SHans de Goede #define DMARD10_REG_MISC2 0x1f 20569906e2SHans de Goede #define DMARD10_REG_PD 0x21 21569906e2SHans de Goede 22569906e2SHans de Goede #define DMARD10_MODE_OFF 0x00 23569906e2SHans de Goede #define DMARD10_MODE_STANDBY 0x02 24569906e2SHans de Goede #define DMARD10_MODE_ACTIVE 0x06 25569906e2SHans de Goede #define DMARD10_MODE_READ_OTP 0x12 26569906e2SHans de Goede #define DMARD10_MODE_RESET_DATA_PATH 0x82 27569906e2SHans de Goede 28569906e2SHans de Goede /* AFEN set 1, ATM[2:0]=b'000 (normal), EN_Z/Y/X/T=1 */ 29569906e2SHans de Goede #define DMARD10_VALUE_AFEM_AFEN_NORMAL 0x8f 30569906e2SHans de Goede /* ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) */ 31569906e2SHans de Goede #define DMARD10_VALUE_CKSEL_ODR_100_204 0x74 32569906e2SHans de Goede /* INTC[6:5]=b'00 */ 33569906e2SHans de Goede #define DMARD10_VALUE_INTC 0x00 34569906e2SHans de Goede /* TAP1/TAP2 Average 2 */ 35569906e2SHans de Goede #define DMARD10_VALUE_TAPNS_AVE_2 0x11 36569906e2SHans de Goede 37569906e2SHans de Goede #define DMARD10_VALUE_STADR 0x55 38569906e2SHans de Goede #define DMARD10_VALUE_STAINT 0xaa 39569906e2SHans de Goede #define DMARD10_VALUE_MISC2_OSCA_EN 0x08 40569906e2SHans de Goede #define DMARD10_VALUE_PD_RST 0x52 41569906e2SHans de Goede 42569906e2SHans de Goede /* Offsets into the buffer read in dmard10_read_raw() */ 43569906e2SHans de Goede #define DMARD10_X_OFFSET 1 44569906e2SHans de Goede #define DMARD10_Y_OFFSET 2 45569906e2SHans de Goede #define DMARD10_Z_OFFSET 3 46569906e2SHans de Goede 47569906e2SHans de Goede /* 48569906e2SHans de Goede * a value of + or -128 corresponds to + or - 1G 49569906e2SHans de Goede * scale = 9.81 / 128 = 0.076640625 50569906e2SHans de Goede */ 51569906e2SHans de Goede 52569906e2SHans de Goede static const int dmard10_nscale = 76640625; 53569906e2SHans de Goede 54569906e2SHans de Goede #define DMARD10_CHANNEL(reg, axis) { \ 55569906e2SHans de Goede .type = IIO_ACCEL, \ 56569906e2SHans de Goede .address = reg, \ 57569906e2SHans de Goede .modified = 1, \ 58569906e2SHans de Goede .channel2 = IIO_MOD_##axis, \ 59569906e2SHans de Goede .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 60569906e2SHans de Goede .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 61569906e2SHans de Goede } 62569906e2SHans de Goede 63569906e2SHans de Goede static const struct iio_chan_spec dmard10_channels[] = { 64569906e2SHans de Goede DMARD10_CHANNEL(DMARD10_X_OFFSET, X), 65569906e2SHans de Goede DMARD10_CHANNEL(DMARD10_Y_OFFSET, Y), 66569906e2SHans de Goede DMARD10_CHANNEL(DMARD10_Z_OFFSET, Z), 67569906e2SHans de Goede }; 68569906e2SHans de Goede 69569906e2SHans de Goede struct dmard10_data { 70569906e2SHans de Goede struct i2c_client *client; 71569906e2SHans de Goede }; 72569906e2SHans de Goede 73569906e2SHans de Goede /* Init sequence taken from the android driver */ 74569906e2SHans de Goede static int dmard10_reset(struct i2c_client *client) 75569906e2SHans de Goede { 76569906e2SHans de Goede unsigned char buffer[7]; 77569906e2SHans de Goede int ret; 78569906e2SHans de Goede 79569906e2SHans de Goede /* 1. Powerdown reset */ 80569906e2SHans de Goede ret = i2c_smbus_write_byte_data(client, DMARD10_REG_PD, 81569906e2SHans de Goede DMARD10_VALUE_PD_RST); 82569906e2SHans de Goede if (ret < 0) 83569906e2SHans de Goede return ret; 84569906e2SHans de Goede 85569906e2SHans de Goede /* 86569906e2SHans de Goede * 2. ACTR => Standby mode => Download OTP to parameter reg => 87569906e2SHans de Goede * Standby mode => Reset data path => Standby mode 88569906e2SHans de Goede */ 89569906e2SHans de Goede buffer[0] = DMARD10_REG_ACTR; 90569906e2SHans de Goede buffer[1] = DMARD10_MODE_STANDBY; 91569906e2SHans de Goede buffer[2] = DMARD10_MODE_READ_OTP; 92569906e2SHans de Goede buffer[3] = DMARD10_MODE_STANDBY; 93569906e2SHans de Goede buffer[4] = DMARD10_MODE_RESET_DATA_PATH; 94569906e2SHans de Goede buffer[5] = DMARD10_MODE_STANDBY; 95569906e2SHans de Goede ret = i2c_master_send(client, buffer, 6); 96569906e2SHans de Goede if (ret < 0) 97569906e2SHans de Goede return ret; 98569906e2SHans de Goede 99569906e2SHans de Goede /* 3. OSCA_EN = 1, TSTO = b'000 (INT1 = normal, TEST0 = normal) */ 100569906e2SHans de Goede ret = i2c_smbus_write_byte_data(client, DMARD10_REG_MISC2, 101569906e2SHans de Goede DMARD10_VALUE_MISC2_OSCA_EN); 102569906e2SHans de Goede if (ret < 0) 103569906e2SHans de Goede return ret; 104569906e2SHans de Goede 105569906e2SHans de Goede /* 4. AFEN = 1 (AFE will powerdown after ADC) */ 106569906e2SHans de Goede buffer[0] = DMARD10_REG_AFEM; 107569906e2SHans de Goede buffer[1] = DMARD10_VALUE_AFEM_AFEN_NORMAL; 108569906e2SHans de Goede buffer[2] = DMARD10_VALUE_CKSEL_ODR_100_204; 109569906e2SHans de Goede buffer[3] = DMARD10_VALUE_INTC; 110569906e2SHans de Goede buffer[4] = DMARD10_VALUE_TAPNS_AVE_2; 111569906e2SHans de Goede buffer[5] = 0x00; /* DLYC, no delay timing */ 112569906e2SHans de Goede buffer[6] = 0x07; /* INTD=1 push-pull, INTA=1 active high, AUTOT=1 */ 113569906e2SHans de Goede ret = i2c_master_send(client, buffer, 7); 114569906e2SHans de Goede if (ret < 0) 115569906e2SHans de Goede return ret; 116569906e2SHans de Goede 117569906e2SHans de Goede /* 5. Activation mode */ 118569906e2SHans de Goede ret = i2c_smbus_write_byte_data(client, DMARD10_REG_ACTR, 119569906e2SHans de Goede DMARD10_MODE_ACTIVE); 120569906e2SHans de Goede if (ret < 0) 121569906e2SHans de Goede return ret; 122569906e2SHans de Goede 123569906e2SHans de Goede return 0; 124569906e2SHans de Goede } 125569906e2SHans de Goede 126569906e2SHans de Goede /* Shutdown sequence taken from the android driver */ 127569906e2SHans de Goede static int dmard10_shutdown(struct i2c_client *client) 128569906e2SHans de Goede { 129569906e2SHans de Goede unsigned char buffer[3]; 130569906e2SHans de Goede 131569906e2SHans de Goede buffer[0] = DMARD10_REG_ACTR; 132569906e2SHans de Goede buffer[1] = DMARD10_MODE_STANDBY; 133569906e2SHans de Goede buffer[2] = DMARD10_MODE_OFF; 134569906e2SHans de Goede 135569906e2SHans de Goede return i2c_master_send(client, buffer, 3); 136569906e2SHans de Goede } 137569906e2SHans de Goede 138569906e2SHans de Goede static int dmard10_read_raw(struct iio_dev *indio_dev, 139569906e2SHans de Goede struct iio_chan_spec const *chan, 140569906e2SHans de Goede int *val, int *val2, long mask) 141569906e2SHans de Goede { 142569906e2SHans de Goede struct dmard10_data *data = iio_priv(indio_dev); 143569906e2SHans de Goede __le16 buf[4]; 144569906e2SHans de Goede int ret; 145569906e2SHans de Goede 146569906e2SHans de Goede switch (mask) { 147569906e2SHans de Goede case IIO_CHAN_INFO_RAW: 148569906e2SHans de Goede /* 149569906e2SHans de Goede * Read 8 bytes starting at the REG_STADR register, trying to 150569906e2SHans de Goede * read the individual X, Y, Z registers will always read 0. 151569906e2SHans de Goede */ 152569906e2SHans de Goede ret = i2c_smbus_read_i2c_block_data(data->client, 153569906e2SHans de Goede DMARD10_REG_STADR, 154569906e2SHans de Goede sizeof(buf), (u8 *)buf); 155569906e2SHans de Goede if (ret < 0) 156569906e2SHans de Goede return ret; 157569906e2SHans de Goede ret = le16_to_cpu(buf[chan->address]); 158569906e2SHans de Goede *val = sign_extend32(ret, 12); 159569906e2SHans de Goede return IIO_VAL_INT; 160569906e2SHans de Goede case IIO_CHAN_INFO_SCALE: 161569906e2SHans de Goede *val = 0; 162569906e2SHans de Goede *val2 = dmard10_nscale; 163569906e2SHans de Goede return IIO_VAL_INT_PLUS_NANO; 164569906e2SHans de Goede default: 165569906e2SHans de Goede return -EINVAL; 166569906e2SHans de Goede } 167569906e2SHans de Goede } 168569906e2SHans de Goede 169569906e2SHans de Goede static const struct iio_info dmard10_info = { 170569906e2SHans de Goede .read_raw = dmard10_read_raw, 171569906e2SHans de Goede }; 172569906e2SHans de Goede 173689f584bSAlexandru Ardelean static void dmard10_shutdown_cleanup(void *client) 174689f584bSAlexandru Ardelean { 175689f584bSAlexandru Ardelean dmard10_shutdown(client); 176689f584bSAlexandru Ardelean } 177689f584bSAlexandru Ardelean 178*5019025fSUwe Kleine-König static int dmard10_probe(struct i2c_client *client) 179569906e2SHans de Goede { 180569906e2SHans de Goede int ret; 181569906e2SHans de Goede struct iio_dev *indio_dev; 182569906e2SHans de Goede struct dmard10_data *data; 183569906e2SHans de Goede 184569906e2SHans de Goede /* These 2 registers have special POR reset values used for id */ 185569906e2SHans de Goede ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STADR); 186569906e2SHans de Goede if (ret != DMARD10_VALUE_STADR) 187569906e2SHans de Goede return (ret < 0) ? ret : -ENODEV; 188569906e2SHans de Goede 189569906e2SHans de Goede ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STAINT); 190569906e2SHans de Goede if (ret != DMARD10_VALUE_STAINT) 191569906e2SHans de Goede return (ret < 0) ? ret : -ENODEV; 192569906e2SHans de Goede 193569906e2SHans de Goede indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 194569906e2SHans de Goede if (!indio_dev) { 195569906e2SHans de Goede dev_err(&client->dev, "iio allocation failed!\n"); 196569906e2SHans de Goede return -ENOMEM; 197569906e2SHans de Goede } 198569906e2SHans de Goede 199569906e2SHans de Goede data = iio_priv(indio_dev); 200569906e2SHans de Goede data->client = client; 201569906e2SHans de Goede 202569906e2SHans de Goede indio_dev->info = &dmard10_info; 203569906e2SHans de Goede indio_dev->name = "dmard10"; 204569906e2SHans de Goede indio_dev->modes = INDIO_DIRECT_MODE; 205569906e2SHans de Goede indio_dev->channels = dmard10_channels; 206569906e2SHans de Goede indio_dev->num_channels = ARRAY_SIZE(dmard10_channels); 207569906e2SHans de Goede 208569906e2SHans de Goede ret = dmard10_reset(client); 209569906e2SHans de Goede if (ret < 0) 210569906e2SHans de Goede return ret; 211569906e2SHans de Goede 212689f584bSAlexandru Ardelean ret = devm_add_action_or_reset(&client->dev, dmard10_shutdown_cleanup, 213689f584bSAlexandru Ardelean client); 214689f584bSAlexandru Ardelean if (ret) 215569906e2SHans de Goede return ret; 216569906e2SHans de Goede 217689f584bSAlexandru Ardelean return devm_iio_device_register(&client->dev, indio_dev); 218569906e2SHans de Goede } 219569906e2SHans de Goede 220569906e2SHans de Goede static int dmard10_suspend(struct device *dev) 221569906e2SHans de Goede { 222569906e2SHans de Goede return dmard10_shutdown(to_i2c_client(dev)); 223569906e2SHans de Goede } 224569906e2SHans de Goede 225569906e2SHans de Goede static int dmard10_resume(struct device *dev) 226569906e2SHans de Goede { 227569906e2SHans de Goede return dmard10_reset(to_i2c_client(dev)); 228569906e2SHans de Goede } 229569906e2SHans de Goede 23050bc5e78SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, 23150bc5e78SJonathan Cameron dmard10_resume); 232569906e2SHans de Goede 233569906e2SHans de Goede static const struct i2c_device_id dmard10_i2c_id[] = { 234569906e2SHans de Goede {"dmard10", 0}, 235569906e2SHans de Goede {} 236569906e2SHans de Goede }; 237569906e2SHans de Goede MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); 238569906e2SHans de Goede 239569906e2SHans de Goede static struct i2c_driver dmard10_driver = { 240569906e2SHans de Goede .driver = { 241569906e2SHans de Goede .name = "dmard10", 24250bc5e78SJonathan Cameron .pm = pm_sleep_ptr(&dmard10_pm_ops), 243569906e2SHans de Goede }, 244*5019025fSUwe Kleine-König .probe_new = dmard10_probe, 245569906e2SHans de Goede .id_table = dmard10_i2c_id, 246569906e2SHans de Goede }; 247569906e2SHans de Goede 248569906e2SHans de Goede module_i2c_driver(dmard10_driver); 249569906e2SHans de Goede 250569906e2SHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 251569906e2SHans de Goede MODULE_DESCRIPTION("Domintech ARD10 3-Axis Accelerometer driver"); 252569906e2SHans de Goede MODULE_LICENSE("GPL v2"); 253