162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * itg3200_buffer.c -- support InvenSense ITG3200 462306a36Sopenharmony_ci * Digital 3-Axis Gyroscope driver 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2011 Christian Strobel <christian.strobel@iis.fraunhofer.de> 762306a36Sopenharmony_ci * Copyright (c) 2011 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> 862306a36Sopenharmony_ci * Copyright (c) 2012 Thorsten Nowak <thorsten.nowak@iis.fraunhofer.de> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/iio/iio.h> 1662306a36Sopenharmony_ci#include <linux/iio/buffer.h> 1762306a36Sopenharmony_ci#include <linux/iio/trigger.h> 1862306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 1962306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 2062306a36Sopenharmony_ci#include <linux/iio/gyro/itg3200.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int itg3200_read_all_channels(struct i2c_client *i2c, __be16 *buf) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci u8 tx = 0x80 | ITG3200_REG_TEMP_OUT_H; 2662306a36Sopenharmony_ci struct i2c_msg msg[2] = { 2762306a36Sopenharmony_ci { 2862306a36Sopenharmony_ci .addr = i2c->addr, 2962306a36Sopenharmony_ci .flags = i2c->flags, 3062306a36Sopenharmony_ci .len = 1, 3162306a36Sopenharmony_ci .buf = &tx, 3262306a36Sopenharmony_ci }, 3362306a36Sopenharmony_ci { 3462306a36Sopenharmony_ci .addr = i2c->addr, 3562306a36Sopenharmony_ci .flags = i2c->flags | I2C_M_RD, 3662306a36Sopenharmony_ci .len = ITG3200_SCAN_ELEMENTS * sizeof(s16), 3762306a36Sopenharmony_ci .buf = (char *)&buf, 3862306a36Sopenharmony_ci }, 3962306a36Sopenharmony_ci }; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return i2c_transfer(i2c->adapter, msg, 2); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic irqreturn_t itg3200_trigger_handler(int irq, void *p) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct iio_poll_func *pf = p; 4762306a36Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 4862306a36Sopenharmony_ci struct itg3200 *st = iio_priv(indio_dev); 4962306a36Sopenharmony_ci /* 5062306a36Sopenharmony_ci * Ensure correct alignment and padding including for the 5162306a36Sopenharmony_ci * timestamp that may be inserted. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci struct { 5462306a36Sopenharmony_ci __be16 buf[ITG3200_SCAN_ELEMENTS]; 5562306a36Sopenharmony_ci s64 ts __aligned(8); 5662306a36Sopenharmony_ci } scan; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci int ret = itg3200_read_all_channels(st->i2c, scan.buf); 5962306a36Sopenharmony_ci if (ret < 0) 6062306a36Sopenharmony_ci goto error_ret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cierror_ret: 6562306a36Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return IRQ_HANDLED; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciint itg3200_buffer_configure(struct iio_dev *indio_dev) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, 7362306a36Sopenharmony_ci itg3200_trigger_handler, NULL); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_civoid itg3200_buffer_unconfigure(struct iio_dev *indio_dev) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int itg3200_data_rdy_trigger_set_state(struct iio_trigger *trig, 8362306a36Sopenharmony_ci bool state) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 8662306a36Sopenharmony_ci int ret; 8762306a36Sopenharmony_ci u8 msc; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_IRQ_CONFIG, &msc); 9062306a36Sopenharmony_ci if (ret) 9162306a36Sopenharmony_ci goto error_ret; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (state) 9462306a36Sopenharmony_ci msc |= ITG3200_IRQ_DATA_RDY_ENABLE; 9562306a36Sopenharmony_ci else 9662306a36Sopenharmony_ci msc &= ~ITG3200_IRQ_DATA_RDY_ENABLE; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = itg3200_write_reg_8(indio_dev, ITG3200_REG_IRQ_CONFIG, msc); 9962306a36Sopenharmony_ci if (ret) 10062306a36Sopenharmony_ci goto error_ret; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cierror_ret: 10362306a36Sopenharmony_ci return ret; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic const struct iio_trigger_ops itg3200_trigger_ops = { 10862306a36Sopenharmony_ci .set_trigger_state = &itg3200_data_rdy_trigger_set_state, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciint itg3200_probe_trigger(struct iio_dev *indio_dev) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int ret; 11462306a36Sopenharmony_ci struct itg3200 *st = iio_priv(indio_dev); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci st->trig = iio_trigger_alloc(&st->i2c->dev, "%s-dev%d", indio_dev->name, 11762306a36Sopenharmony_ci iio_device_id(indio_dev)); 11862306a36Sopenharmony_ci if (!st->trig) 11962306a36Sopenharmony_ci return -ENOMEM; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ret = request_irq(st->i2c->irq, 12262306a36Sopenharmony_ci &iio_trigger_generic_data_rdy_poll, 12362306a36Sopenharmony_ci IRQF_TRIGGER_RISING, 12462306a36Sopenharmony_ci "itg3200_data_rdy", 12562306a36Sopenharmony_ci st->trig); 12662306a36Sopenharmony_ci if (ret) 12762306a36Sopenharmony_ci goto error_free_trig; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci st->trig->ops = &itg3200_trigger_ops; 13162306a36Sopenharmony_ci iio_trigger_set_drvdata(st->trig, indio_dev); 13262306a36Sopenharmony_ci ret = iio_trigger_register(st->trig); 13362306a36Sopenharmony_ci if (ret) 13462306a36Sopenharmony_ci goto error_free_irq; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* select default trigger */ 13762306a36Sopenharmony_ci indio_dev->trig = iio_trigger_get(st->trig); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cierror_free_irq: 14262306a36Sopenharmony_ci free_irq(st->i2c->irq, st->trig); 14362306a36Sopenharmony_cierror_free_trig: 14462306a36Sopenharmony_ci iio_trigger_free(st->trig); 14562306a36Sopenharmony_ci return ret; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_civoid itg3200_remove_trigger(struct iio_dev *indio_dev) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct itg3200 *st = iio_priv(indio_dev); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci iio_trigger_unregister(st->trig); 15362306a36Sopenharmony_ci free_irq(st->i2c->irq, st->trig); 15462306a36Sopenharmony_ci iio_trigger_free(st->trig); 15562306a36Sopenharmony_ci} 156