Commit 08a65f61 authored by Marcus Folkesson's avatar Marcus Folkesson Committed by Jonathan Cameron
Browse files

iio: adc: mcp3911: add support for interrupts



Make it possible to read values upon interrupts.
Configure Data Ready Signal Output Pin to either HiZ or push-pull and
use it as interrupt source.

Signed-off-by: default avatarMarcus Folkesson <marcus.folkesson@gmail.com>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20220815061625.35568-7-marcus.folkesson@gmail.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 5db9f38d
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#define MCP3911_REG_GAIN		0x09

#define MCP3911_REG_STATUSCOM		0x0a
#define MCP3911_STATUSCOM_DRHIZ         BIT(12)
#define MCP3911_STATUSCOM_READ		GENMASK(7, 6)
#define MCP3911_STATUSCOM_CH1_24WIDTH	BIT(4)
#define MCP3911_STATUSCOM_CH0_24WIDTH	BIT(3)
@@ -64,6 +65,7 @@ struct mcp3911 {
	struct regulator *vref;
	struct clk *clki;
	u32 dev_addr;
	struct iio_trigger *trig;
	struct {
		u32 channels[MCP3911_NUM_CHANNELS];
		s64 ts __aligned(8);
@@ -344,6 +346,23 @@ static void mcp3911_cleanup_regulator(void *vref)
	regulator_disable(vref);
}

static int mcp3911_set_trigger_state(struct iio_trigger *trig, bool enable)
{
	struct mcp3911 *adc = iio_trigger_get_drvdata(trig);

	if (enable)
		enable_irq(adc->spi->irq);
	else
		disable_irq(adc->spi->irq);

	return 0;
}

static const struct iio_trigger_ops mcp3911_trigger_ops = {
	.validate_device = iio_trigger_validate_own_device,
	.set_trigger_state = mcp3911_set_trigger_state,
};

static int mcp3911_probe(struct spi_device *spi)
{
	struct iio_dev *indio_dev;
@@ -395,6 +414,15 @@ static int mcp3911_probe(struct spi_device *spi)
	if (ret)
		return ret;

	if (device_property_read_bool(&adc->spi->dev, "microchip,data-ready-hiz"))
		ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
				0, 2);
	else
		ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
				MCP3911_STATUSCOM_DRHIZ, 2);
	if (ret)
		return ret;

	indio_dev->name = spi_get_device_id(spi)->name;
	indio_dev->modes = INDIO_DIRECT_MODE;
	indio_dev->info = &mcp3911_info;
@@ -405,6 +433,31 @@ static int mcp3911_probe(struct spi_device *spi)

	mutex_init(&adc->lock);

	if (spi->irq > 0) {
		adc->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
				indio_dev->name,
				iio_device_id(indio_dev));
		if (!adc->trig)
			return PTR_ERR(adc->trig);

		adc->trig->ops = &mcp3911_trigger_ops;
		iio_trigger_set_drvdata(adc->trig, adc);
		ret = devm_iio_trigger_register(&spi->dev, adc->trig);
		if (ret)
			return ret;

		/*
		 * The device generates interrupts as long as it is powered up.
		 * Some platforms might not allow the option to power it down so
		 * don't enable the interrupt to avoid extra load on the system.
		 */
		ret = devm_request_irq(&spi->dev, spi->irq,
				&iio_trigger_generic_data_rdy_poll, IRQF_NO_AUTOEN | IRQF_ONESHOT,
				indio_dev->name, adc->trig);
		if (ret)
			return ret;
	}

	ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
			NULL,
			mcp3911_trigger_handler, NULL);