0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/delay.h>
0013 #include <linux/i2c.h>
0014 #include <linux/iio/iio.h>
0015 #include <linux/iio/buffer.h>
0016 #include <linux/iio/trigger_consumer.h>
0017 #include <linux/iio/triggered_buffer.h>
0018 #include <asm/unaligned.h>
0019
0020
0021 #define DLH_START_SINGLE 0xAA
0022
0023
0024 #define DLH_STATUS_OK 0x40
0025
0026
0027 #define DLH_NUM_READ_BYTES 7
0028 #define DLH_NUM_DATA_BYTES 3
0029 #define DLH_NUM_PR_BITS 24
0030 #define DLH_NUM_TEMP_BITS 24
0031
0032
0033 #define DLH_SINGLE_DUT_MS 5
0034
0035 enum dhl_ids {
0036 dlhl60d,
0037 dlhl60g,
0038 };
0039
0040 struct dlh_info {
0041 u8 osdig;
0042 unsigned int fss;
0043 };
0044
0045 struct dlh_state {
0046 struct i2c_client *client;
0047 struct dlh_info info;
0048 bool use_interrupt;
0049 struct completion completion;
0050 u8 rx_buf[DLH_NUM_READ_BYTES];
0051 };
0052
0053 static struct dlh_info dlh_info_tbl[] = {
0054 [dlhl60d] = {
0055 .osdig = 2,
0056 .fss = 120,
0057 },
0058 [dlhl60g] = {
0059 .osdig = 10,
0060 .fss = 60,
0061 },
0062 };
0063
0064
0065 static int dlh_cmd_start_single(struct dlh_state *st)
0066 {
0067 int ret;
0068
0069 ret = i2c_smbus_write_byte(st->client, DLH_START_SINGLE);
0070 if (ret)
0071 dev_err(&st->client->dev,
0072 "%s: I2C write byte failed\n", __func__);
0073
0074 return ret;
0075 }
0076
0077 static int dlh_cmd_read_data(struct dlh_state *st)
0078 {
0079 int ret;
0080
0081 ret = i2c_master_recv(st->client, st->rx_buf, DLH_NUM_READ_BYTES);
0082 if (ret < 0) {
0083 dev_err(&st->client->dev,
0084 "%s: I2C read block failed\n", __func__);
0085 return ret;
0086 }
0087
0088 if (st->rx_buf[0] != DLH_STATUS_OK) {
0089 dev_err(&st->client->dev,
0090 "%s: invalid status 0x%02x\n", __func__, st->rx_buf[0]);
0091 return -EBUSY;
0092 }
0093
0094 return 0;
0095 }
0096
0097 static int dlh_start_capture_and_read(struct dlh_state *st)
0098 {
0099 int ret;
0100
0101 if (st->use_interrupt)
0102 reinit_completion(&st->completion);
0103
0104 ret = dlh_cmd_start_single(st);
0105 if (ret)
0106 return ret;
0107
0108 if (st->use_interrupt) {
0109 ret = wait_for_completion_timeout(&st->completion,
0110 msecs_to_jiffies(DLH_SINGLE_DUT_MS));
0111 if (!ret) {
0112 dev_err(&st->client->dev,
0113 "%s: conversion timed out\n", __func__);
0114 return -ETIMEDOUT;
0115 }
0116 } else {
0117 mdelay(DLH_SINGLE_DUT_MS);
0118 }
0119
0120 return dlh_cmd_read_data(st);
0121 }
0122
0123 static int dlh_read_direct(struct dlh_state *st,
0124 unsigned int *pressure, unsigned int *temperature)
0125 {
0126 int ret;
0127
0128 ret = dlh_start_capture_and_read(st);
0129 if (ret)
0130 return ret;
0131
0132 *pressure = get_unaligned_be32(&st->rx_buf[1]) >> 8;
0133 *temperature = get_unaligned_be32(&st->rx_buf[3]) &
0134 GENMASK(DLH_NUM_TEMP_BITS - 1, 0);
0135
0136 return 0;
0137 }
0138
0139 static int dlh_read_raw(struct iio_dev *indio_dev,
0140 struct iio_chan_spec const *channel, int *value,
0141 int *value2, long mask)
0142 {
0143 struct dlh_state *st = iio_priv(indio_dev);
0144 unsigned int pressure, temperature;
0145 int ret;
0146 s64 tmp;
0147 s32 rem;
0148
0149 switch (mask) {
0150 case IIO_CHAN_INFO_RAW:
0151 ret = iio_device_claim_direct_mode(indio_dev);
0152 if (ret)
0153 return ret;
0154
0155 ret = dlh_read_direct(st, &pressure, &temperature);
0156 iio_device_release_direct_mode(indio_dev);
0157 if (ret)
0158 return ret;
0159
0160 switch (channel->type) {
0161 case IIO_PRESSURE:
0162 *value = pressure;
0163 return IIO_VAL_INT;
0164
0165 case IIO_TEMP:
0166 *value = temperature;
0167 return IIO_VAL_INT;
0168
0169 default:
0170 return -EINVAL;
0171 }
0172 case IIO_CHAN_INFO_SCALE:
0173 switch (channel->type) {
0174 case IIO_PRESSURE:
0175 tmp = div_s64(125LL * st->info.fss * 24909 * 100,
0176 1 << DLH_NUM_PR_BITS);
0177 tmp = div_s64_rem(tmp, 1000000000LL, &rem);
0178 *value = tmp;
0179 *value2 = rem;
0180 return IIO_VAL_INT_PLUS_NANO;
0181
0182 case IIO_TEMP:
0183 *value = 125 * 1000;
0184 *value2 = DLH_NUM_TEMP_BITS;
0185 return IIO_VAL_FRACTIONAL_LOG2;
0186
0187 default:
0188 return -EINVAL;
0189 }
0190 case IIO_CHAN_INFO_OFFSET:
0191 switch (channel->type) {
0192 case IIO_PRESSURE:
0193 *value = -125 * st->info.fss * 24909;
0194 *value2 = 100 * st->info.osdig * 100000;
0195 return IIO_VAL_FRACTIONAL;
0196
0197 case IIO_TEMP:
0198 *value = -40 * 1000;
0199 return IIO_VAL_INT;
0200
0201 default:
0202 return -EINVAL;
0203 }
0204 }
0205
0206 return -EINVAL;
0207 }
0208
0209 static const struct iio_info dlh_info = {
0210 .read_raw = dlh_read_raw,
0211 };
0212
0213 static const struct iio_chan_spec dlh_channels[] = {
0214 {
0215 .type = IIO_PRESSURE,
0216 .indexed = 1,
0217 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0218 .info_mask_shared_by_type =
0219 BIT(IIO_CHAN_INFO_SCALE) |
0220 BIT(IIO_CHAN_INFO_OFFSET),
0221 .scan_index = 0,
0222 .scan_type = {
0223 .sign = 'u',
0224 .realbits = DLH_NUM_PR_BITS,
0225 .storagebits = 32,
0226 .shift = 8,
0227 .endianness = IIO_BE,
0228 },
0229 }, {
0230 .type = IIO_TEMP,
0231 .indexed = 1,
0232 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0233 .info_mask_shared_by_type =
0234 BIT(IIO_CHAN_INFO_SCALE) |
0235 BIT(IIO_CHAN_INFO_OFFSET),
0236 .scan_index = 1,
0237 .scan_type = {
0238 .sign = 'u',
0239 .realbits = DLH_NUM_TEMP_BITS,
0240 .storagebits = 32,
0241 .shift = 8,
0242 .endianness = IIO_BE,
0243 },
0244 }
0245 };
0246
0247 static irqreturn_t dlh_trigger_handler(int irq, void *private)
0248 {
0249 struct iio_poll_func *pf = private;
0250 struct iio_dev *indio_dev = pf->indio_dev;
0251 struct dlh_state *st = iio_priv(indio_dev);
0252 int ret;
0253 unsigned int chn, i = 0;
0254 __be32 tmp_buf[2];
0255
0256 ret = dlh_start_capture_and_read(st);
0257 if (ret)
0258 goto out;
0259
0260 for_each_set_bit(chn, indio_dev->active_scan_mask,
0261 indio_dev->masklength) {
0262 memcpy(tmp_buf + i,
0263 &st->rx_buf[1] + chn * DLH_NUM_DATA_BYTES,
0264 DLH_NUM_DATA_BYTES);
0265 i++;
0266 }
0267
0268 iio_push_to_buffers(indio_dev, tmp_buf);
0269
0270 out:
0271 iio_trigger_notify_done(indio_dev->trig);
0272
0273 return IRQ_HANDLED;
0274 }
0275
0276 static irqreturn_t dlh_interrupt(int irq, void *private)
0277 {
0278 struct iio_dev *indio_dev = private;
0279 struct dlh_state *st = iio_priv(indio_dev);
0280
0281 complete(&st->completion);
0282
0283 return IRQ_HANDLED;
0284 };
0285
0286 static int dlh_probe(struct i2c_client *client,
0287 const struct i2c_device_id *id)
0288 {
0289 struct dlh_state *st;
0290 struct iio_dev *indio_dev;
0291 int ret;
0292
0293 if (!i2c_check_functionality(client->adapter,
0294 I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE)) {
0295 dev_err(&client->dev,
0296 "adapter doesn't support required i2c functionality\n");
0297 return -EOPNOTSUPP;
0298 }
0299
0300 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
0301 if (!indio_dev) {
0302 dev_err(&client->dev, "failed to allocate iio device\n");
0303 return -ENOMEM;
0304 }
0305
0306 i2c_set_clientdata(client, indio_dev);
0307
0308 st = iio_priv(indio_dev);
0309 st->info = dlh_info_tbl[id->driver_data];
0310 st->client = client;
0311 st->use_interrupt = false;
0312
0313 indio_dev->name = id->name;
0314 indio_dev->info = &dlh_info;
0315 indio_dev->modes = INDIO_DIRECT_MODE;
0316 indio_dev->channels = dlh_channels;
0317 indio_dev->num_channels = ARRAY_SIZE(dlh_channels);
0318
0319 if (client->irq > 0) {
0320 ret = devm_request_threaded_irq(&client->dev, client->irq,
0321 dlh_interrupt, NULL,
0322 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
0323 id->name, indio_dev);
0324 if (ret) {
0325 dev_err(&client->dev, "failed to allocate threaded irq");
0326 return ret;
0327 }
0328
0329 st->use_interrupt = true;
0330 init_completion(&st->completion);
0331 }
0332
0333 ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
0334 NULL, &dlh_trigger_handler, NULL);
0335 if (ret) {
0336 dev_err(&client->dev, "failed to setup iio buffer\n");
0337 return ret;
0338 }
0339
0340 ret = devm_iio_device_register(&client->dev, indio_dev);
0341 if (ret)
0342 dev_err(&client->dev, "failed to register iio device\n");
0343
0344 return ret;
0345 }
0346
0347 static const struct of_device_id dlh_of_match[] = {
0348 { .compatible = "asc,dlhl60d" },
0349 { .compatible = "asc,dlhl60g" },
0350 {}
0351 };
0352 MODULE_DEVICE_TABLE(of, dlh_of_match);
0353
0354 static const struct i2c_device_id dlh_id[] = {
0355 { "dlhl60d", dlhl60d },
0356 { "dlhl60g", dlhl60g },
0357 {}
0358 };
0359 MODULE_DEVICE_TABLE(i2c, dlh_id);
0360
0361 static struct i2c_driver dlh_driver = {
0362 .driver = {
0363 .name = "dlhl60d",
0364 .of_match_table = dlh_of_match,
0365 },
0366 .probe = dlh_probe,
0367 .id_table = dlh_id,
0368 };
0369 module_i2c_driver(dlh_driver);
0370
0371 MODULE_AUTHOR("Tomislav Denis <tomislav.denis@avl.com>");
0372 MODULE_DESCRIPTION("Driver for All Sensors DLH series pressure sensors");
0373 MODULE_LICENSE("GPL v2");