123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /*
- * IIO driver for Domintech DMARD06 accelerometer
- *
- * Copyright (C) 2016 Aleksei Mamlin <mamlinav@gmail.com>
- *
- * 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.
- */
- #include <linux/module.h>
- #include <linux/i2c.h>
- #include <linux/iio/iio.h>
- #define DMARD06_DRV_NAME "dmard06"
- /* Device data registers */
- #define DMARD06_CHIP_ID_REG 0x0f
- #define DMARD06_TOUT_REG 0x40
- #define DMARD06_XOUT_REG 0x41
- #define DMARD06_YOUT_REG 0x42
- #define DMARD06_ZOUT_REG 0x43
- #define DMARD06_CTRL1_REG 0x44
- /* Device ID value */
- #define DMARD05_CHIP_ID 0x05
- #define DMARD06_CHIP_ID 0x06
- #define DMARD07_CHIP_ID 0x07
- /* Device values */
- #define DMARD05_AXIS_SCALE_VAL 15625
- #define DMARD06_AXIS_SCALE_VAL 31250
- #define DMARD06_TEMP_CENTER_VAL 25
- #define DMARD06_SIGN_BIT 7
- /* Device power modes */
- #define DMARD06_MODE_NORMAL 0x27
- #define DMARD06_MODE_POWERDOWN 0x00
- /* Device channels */
- #define DMARD06_ACCEL_CHANNEL(_axis, _reg) { \
- .type = IIO_ACCEL, \
- .address = _reg, \
- .channel2 = IIO_MOD_##_axis, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .modified = 1, \
- }
- #define DMARD06_TEMP_CHANNEL(_reg) { \
- .type = IIO_TEMP, \
- .address = _reg, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_OFFSET), \
- }
- struct dmard06_data {
- struct i2c_client *client;
- u8 chip_id;
- };
- static const struct iio_chan_spec dmard06_channels[] = {
- DMARD06_ACCEL_CHANNEL(X, DMARD06_XOUT_REG),
- DMARD06_ACCEL_CHANNEL(Y, DMARD06_YOUT_REG),
- DMARD06_ACCEL_CHANNEL(Z, DMARD06_ZOUT_REG),
- DMARD06_TEMP_CHANNEL(DMARD06_TOUT_REG),
- };
- static int dmard06_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
- {
- struct dmard06_data *dmard06 = iio_priv(indio_dev);
- int ret;
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- ret = i2c_smbus_read_byte_data(dmard06->client,
- chan->address);
- if (ret < 0) {
- dev_err(&dmard06->client->dev,
- "Error reading data: %d\n", ret);
- return ret;
- }
- *val = sign_extend32(ret, DMARD06_SIGN_BIT);
- if (dmard06->chip_id == DMARD06_CHIP_ID)
- *val = *val >> 1;
- switch (chan->type) {
- case IIO_ACCEL:
- return IIO_VAL_INT;
- case IIO_TEMP:
- if (dmard06->chip_id != DMARD06_CHIP_ID)
- *val = *val / 2;
- return IIO_VAL_INT;
- default:
- return -EINVAL;
- }
- case IIO_CHAN_INFO_OFFSET:
- switch (chan->type) {
- case IIO_TEMP:
- *val = DMARD06_TEMP_CENTER_VAL;
- return IIO_VAL_INT;
- default:
- return -EINVAL;
- }
- case IIO_CHAN_INFO_SCALE:
- switch (chan->type) {
- case IIO_ACCEL:
- *val = 0;
- if (dmard06->chip_id == DMARD06_CHIP_ID)
- *val2 = DMARD06_AXIS_SCALE_VAL;
- else
- *val2 = DMARD05_AXIS_SCALE_VAL;
- return IIO_VAL_INT_PLUS_MICRO;
- default:
- return -EINVAL;
- }
- default:
- return -EINVAL;
- }
- }
- static const struct iio_info dmard06_info = {
- .driver_module = THIS_MODULE,
- .read_raw = dmard06_read_raw,
- };
- static int dmard06_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- int ret;
- struct iio_dev *indio_dev;
- struct dmard06_data *dmard06;
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev, "I2C check functionality failed\n");
- return -ENXIO;
- }
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dmard06));
- if (!indio_dev) {
- dev_err(&client->dev, "Failed to allocate iio device\n");
- return -ENOMEM;
- }
- dmard06 = iio_priv(indio_dev);
- dmard06->client = client;
- ret = i2c_smbus_read_byte_data(dmard06->client, DMARD06_CHIP_ID_REG);
- if (ret < 0) {
- dev_err(&client->dev, "Error reading chip id: %d\n", ret);
- return ret;
- }
- if (ret != DMARD05_CHIP_ID && ret != DMARD06_CHIP_ID &&
- ret != DMARD07_CHIP_ID) {
- dev_err(&client->dev, "Invalid chip id: %02d\n", ret);
- return -ENODEV;
- }
- dmard06->chip_id = ret;
- i2c_set_clientdata(client, indio_dev);
- indio_dev->dev.parent = &client->dev;
- indio_dev->name = DMARD06_DRV_NAME;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = dmard06_channels;
- indio_dev->num_channels = ARRAY_SIZE(dmard06_channels);
- indio_dev->info = &dmard06_info;
- return devm_iio_device_register(&client->dev, indio_dev);
- }
- #ifdef CONFIG_PM_SLEEP
- static int dmard06_suspend(struct device *dev)
- {
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
- struct dmard06_data *dmard06 = iio_priv(indio_dev);
- int ret;
- ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
- DMARD06_MODE_POWERDOWN);
- if (ret < 0)
- return ret;
- return 0;
- }
- static int dmard06_resume(struct device *dev)
- {
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
- struct dmard06_data *dmard06 = iio_priv(indio_dev);
- int ret;
- ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
- DMARD06_MODE_NORMAL);
- if (ret < 0)
- return ret;
- return 0;
- }
- static SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume);
- #define DMARD06_PM_OPS (&dmard06_pm_ops)
- #else
- #define DMARD06_PM_OPS NULL
- #endif
- static const struct i2c_device_id dmard06_id[] = {
- { "dmard05", 0 },
- { "dmard06", 0 },
- { "dmard07", 0 },
- { }
- };
- MODULE_DEVICE_TABLE(i2c, dmard06_id);
- static const struct of_device_id dmard06_of_match[] = {
- { .compatible = "domintech,dmard05" },
- { .compatible = "domintech,dmard06" },
- { .compatible = "domintech,dmard07" },
- { }
- };
- MODULE_DEVICE_TABLE(of, dmard06_of_match);
- static struct i2c_driver dmard06_driver = {
- .probe = dmard06_probe,
- .id_table = dmard06_id,
- .driver = {
- .name = DMARD06_DRV_NAME,
- .of_match_table = of_match_ptr(dmard06_of_match),
- .pm = DMARD06_PM_OPS,
- },
- };
- module_i2c_driver(dmard06_driver);
- MODULE_AUTHOR("Aleksei Mamlin <mamlinav@gmail.com>");
- MODULE_DESCRIPTION("Domintech DMARD06 accelerometer driver");
- MODULE_LICENSE("GPL v2");
|