File Index
Files and directories
Sign in
FILE

sx_common.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/proximity/sx_common.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright 2021 Google LLC.
  4 *
  5 * Common part of most Semtech SAR sensor.
  6 */
  7
  8#include <linux/bitops.h>
  9#include <linux/byteorder/generic.h>
 10#include <linux/delay.h>
 11#include <linux/device.h>
 12#include <linux/err.h>
 13#include <linux/export.h>
 14#include <linux/interrupt.h>
 15#include <linux/irqreturn.h>
 16#include <linux/i2c.h>
 17#include <linux/kernel.h>
 18#include <linux/module.h>
 19#include <linux/regmap.h>
 20#include <linux/regulator/consumer.h>
 21#include <vdso/bits.h>
 22
 23#include <linux/iio/buffer.h>
 24#include <linux/iio/events.h>
 25#include <linux/iio/iio.h>
 26#include <linux/iio/trigger.h>
 27#include <linux/iio/triggered_buffer.h>
 28#include <linux/iio/trigger_consumer.h>
 29
 30#include "sx_common.h"
 31
 32/* All Semtech SAR sensors have IRQ bit in the same order. */
 33#define   SX_COMMON_CONVDONE_IRQ			BIT(0)
 34#define   SX_COMMON_FAR_IRQ				BIT(2)
 35#define   SX_COMMON_CLOSE_IRQ				BIT(3)
 36
 37const struct iio_event_spec sx_common_events[3] = {
 38	{
 39		.type = IIO_EV_TYPE_THRESH,
 40		.dir = IIO_EV_DIR_RISING,
 41		.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
 42	},
 43	{
 44		.type = IIO_EV_TYPE_THRESH,
 45		.dir = IIO_EV_DIR_FALLING,
 46		.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD),
 47	},
 48	{
 49		.type = IIO_EV_TYPE_THRESH,
 50		.dir = IIO_EV_DIR_EITHER,
 51		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
 52				 BIT(IIO_EV_INFO_HYSTERESIS) |
 53				 BIT(IIO_EV_INFO_VALUE),
 54	},
 55};
 56EXPORT_SYMBOL_NS_GPL(sx_common_events, "SEMTECH_PROX");
 57
 58static irqreturn_t sx_common_irq_handler(int irq, void *private)
 59{
 60	struct iio_dev *indio_dev = private;
 61	struct sx_common_data *data = iio_priv(indio_dev);
 62
 63	if (data->trigger_enabled)
 64		iio_trigger_poll(data->trig);
 65
 66	/*
 67	 * Even if no event is enabled, we need to wake the thread to clear the
 68	 * interrupt state by reading SX_COMMON_REG_IRQ_SRC.
 69	 * It is not possible to do that here because regmap_read takes a mutex.
 70	 */
 71	return IRQ_WAKE_THREAD;
 72}
 73
 74static void sx_common_push_events(struct iio_dev *indio_dev)
 75{
 76	int ret;
 77	unsigned int val, chan;
 78	struct sx_common_data *data = iio_priv(indio_dev);
 79	s64 timestamp = iio_get_time_ns(indio_dev);
 80	unsigned long prox_changed;
 81
 82	/* Read proximity state on all channels */
 83	ret = regmap_read(data->regmap, data->chip_info->reg_stat, &val);
 84	if (ret) {
 85		dev_err(&data->client->dev, "i2c transfer error in irq\n");
 86		return;
 87	}
 88
 89	val >>= data->chip_info->stat_offset;
 90
 91	/*
 92	 * Only iterate over channels with changes on proximity status that have
 93	 * events enabled.
 94	 */
 95	prox_changed = (data->chan_prox_stat ^ val) & data->chan_event;
 96
 97	for_each_set_bit(chan, &prox_changed, data->chip_info->num_channels) {
 98		int dir;
 99		u64 ev;
100
101		dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
102		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
103					  IIO_EV_TYPE_THRESH, dir);
104
105		iio_push_event(indio_dev, ev, timestamp);
106	}
107	data->chan_prox_stat = val;
108}
109
110static int sx_common_enable_irq(struct sx_common_data *data, unsigned int irq)
111{
112	if (!data->client->irq)
113		return 0;
114	return regmap_set_bits(data->regmap, data->chip_info->reg_irq_msk,
115			       irq << data->chip_info->irq_msk_offset);
116}
117
118static int sx_common_disable_irq(struct sx_common_data *data, unsigned int irq)
119{
120	if (!data->client->irq)
121		return 0;
122	return regmap_clear_bits(data->regmap, data->chip_info->reg_irq_msk,
123				 irq << data->chip_info->irq_msk_offset);
124}
125
126static int sx_common_update_chan_en(struct sx_common_data *data,
127				    unsigned long chan_read,
128				    unsigned long chan_event)
129{
130	int ret;
131	unsigned long channels = chan_read | chan_event;
132
133	if ((data->chan_read | data->chan_event) != channels) {
134		ret = regmap_update_bits(data->regmap,
135					 data->chip_info->reg_enable_chan,
136					 data->chip_info->mask_enable_chan,
137					 channels);
138		if (ret)
139			return ret;
140	}
141	data->chan_read = chan_read;
142	data->chan_event = chan_event;
143	return 0;
144}
145
146static int sx_common_get_read_channel(struct sx_common_data *data, int channel)
147{
148	return sx_common_update_chan_en(data, data->chan_read | BIT(channel),
149				     data->chan_event);
150}
151
152static int sx_common_put_read_channel(struct sx_common_data *data, int channel)
153{
154	return sx_common_update_chan_en(data, data->chan_read & ~BIT(channel),
155				     data->chan_event);
156}
157
158static int sx_common_get_event_channel(struct sx_common_data *data, int channel)
159{
160	return sx_common_update_chan_en(data, data->chan_read,
161				     data->chan_event | BIT(channel));
162}
163
164static int sx_common_put_event_channel(struct sx_common_data *data, int channel)
165{
166	return sx_common_update_chan_en(data, data->chan_read,
167				     data->chan_event & ~BIT(channel));
168}
169
170/**
171 * sx_common_read_proximity() - Read raw proximity value.
172 * @data:	Internal data
173 * @chan:	Channel to read
174 * @val:	pointer to return read value.
175 *
176 * Request a conversion, wait for the sensor to be ready and
177 * return the raw proximity value.
178 */
179int sx_common_read_proximity(struct sx_common_data *data,
180			     const struct iio_chan_spec *chan, int *val)
181{
182	int ret;
183	__be16 rawval;
184
185	mutex_lock(&data->mutex);
186
187	ret = sx_common_get_read_channel(data, chan->channel);
188	if (ret)
189		goto out;
190
191	ret = sx_common_enable_irq(data, SX_COMMON_CONVDONE_IRQ);
192	if (ret)
193		goto out_put_channel;
194
195	mutex_unlock(&data->mutex);
196
197	if (data->client->irq) {
198		ret = wait_for_completion_interruptible(&data->completion);
199		reinit_completion(&data->completion);
200	} else {
201		ret = data->chip_info->ops.wait_for_sample(data);
202	}
203
204	mutex_lock(&data->mutex);
205
206	if (ret)
207		goto out_disable_irq;
208
209	ret = data->chip_info->ops.read_prox_data(data, chan, &rawval);
210	if (ret)
211		goto out_disable_irq;
212
213	*val = sign_extend32(be16_to_cpu(rawval), chan->scan_type.realbits - 1);
214
215	ret = sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ);
216	if (ret)
217		goto out_put_channel;
218
219	ret = sx_common_put_read_channel(data, chan->channel);
220	if (ret)
221		goto out;
222
223	mutex_unlock(&data->mutex);
224
225	return IIO_VAL_INT;
226
227out_disable_irq:
228	sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ);
229out_put_channel:
230	sx_common_put_read_channel(data, chan->channel);
231out:
232	mutex_unlock(&data->mutex);
233
234	return ret;
235}
236EXPORT_SYMBOL_NS_GPL(sx_common_read_proximity, "SEMTECH_PROX");
237
238/**
239 * sx_common_read_event_config() - Configure event setting.
240 * @indio_dev:	iio device object
241 * @chan:	Channel to read
242 * @type:	Type of event (unused)
243 * @dir:	Direction of event (unused)
244 *
245 * return if the given channel is used for event gathering.
246 */
247int sx_common_read_event_config(struct iio_dev *indio_dev,
248				const struct iio_chan_spec *chan,
249				enum iio_event_type type,
250				enum iio_event_direction dir)
251{
252	struct sx_common_data *data = iio_priv(indio_dev);
253
254	return !!(data->chan_event & BIT(chan->channel));
255}
256EXPORT_SYMBOL_NS_GPL(sx_common_read_event_config, "SEMTECH_PROX");
257
258/**
259 * sx_common_write_event_config() - Configure event setting.
260 * @indio_dev:	iio device object
261 * @chan:	Channel to enable
262 * @type:	Type of event (unused)
263 * @dir:	Direction of event (unused)
264 * @state:	State of the event.
265 *
266 * Enable/Disable event on a given channel.
267 */
268int sx_common_write_event_config(struct iio_dev *indio_dev,
269				 const struct iio_chan_spec *chan,
270				 enum iio_event_type type,
271				 enum iio_event_direction dir, bool state)
272{
273	struct sx_common_data *data = iio_priv(indio_dev);
274	unsigned int eventirq = SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ;
275	int ret;
276
277	/* If the state hasn't changed, there's nothing to do. */
278	if (!!(data->chan_event & BIT(chan->channel)) == state)
279		return 0;
280
281	mutex_lock(&data->mutex);
282	if (state) {
283		ret = sx_common_get_event_channel(data, chan->channel);
284		if (ret)
285			goto out_unlock;
286		if (!(data->chan_event & ~BIT(chan->channel))) {
287			ret = sx_common_enable_irq(data, eventirq);
288			if (ret)
289				sx_common_put_event_channel(data, chan->channel);
290		}
291	} else {
292		ret = sx_common_put_event_channel(data, chan->channel);
293		if (ret)
294			goto out_unlock;
295		if (!data->chan_event) {
296			ret = sx_common_disable_irq(data, eventirq);
297			if (ret)
298				sx_common_get_event_channel(data, chan->channel);
299		}
300	}
301
302out_unlock:
303	mutex_unlock(&data->mutex);
304	return ret;
305}
306EXPORT_SYMBOL_NS_GPL(sx_common_write_event_config, "SEMTECH_PROX");
307
308static int sx_common_set_trigger_state(struct iio_trigger *trig, bool state)
309{
310	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
311	struct sx_common_data *data = iio_priv(indio_dev);
312	int ret = 0;
313
314	mutex_lock(&data->mutex);
315
316	if (state)
317		ret = sx_common_enable_irq(data, SX_COMMON_CONVDONE_IRQ);
318	else if (!data->chan_read)
319		ret = sx_common_disable_irq(data, SX_COMMON_CONVDONE_IRQ);
320	if (ret)
321		goto out;
322
323	data->trigger_enabled = state;
324
325out:
326	mutex_unlock(&data->mutex);
327
328	return ret;
329}
330
331static const struct iio_trigger_ops sx_common_trigger_ops = {
332	.set_trigger_state = sx_common_set_trigger_state,
333};
334
335static irqreturn_t sx_common_irq_thread_handler(int irq, void *private)
336{
337	struct iio_dev *indio_dev = private;
338	struct sx_common_data *data = iio_priv(indio_dev);
339	int ret;
340	unsigned int val;
341
342	mutex_lock(&data->mutex);
343
344	ret = regmap_read(data->regmap, SX_COMMON_REG_IRQ_SRC, &val);
345	if (ret) {
346		dev_err(&data->client->dev, "i2c transfer error in irq\n");
347		goto out;
348	}
349
350	if (val & ((SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ) << data->chip_info->irq_msk_offset))
351		sx_common_push_events(indio_dev);
352
353	if (val & (SX_COMMON_CONVDONE_IRQ << data->chip_info->irq_msk_offset))
354		complete(&data->completion);
355
356out:
357	mutex_unlock(&data->mutex);
358
359	return IRQ_HANDLED;
360}
361
362static irqreturn_t sx_common_trigger_handler(int irq, void *private)
363{
364	struct iio_poll_func *pf = private;
365	struct iio_dev *indio_dev = pf->indio_dev;
366	struct sx_common_data *data = iio_priv(indio_dev);
367	__be16 val;
368	int bit, ret, i = 0;
369
370	mutex_lock(&data->mutex);
371
372	iio_for_each_active_channel(indio_dev, bit) {
373		ret = data->chip_info->ops.read_prox_data(data,
374						     &indio_dev->channels[bit],
375						     &val);
376		if (ret)
377			goto out;
378
379		data->buffer.channels[i++] = val;
380	}
381
382	iio_push_to_buffers_with_ts(indio_dev, &data->buffer,
383				    sizeof(data->buffer), pf->timestamp);
384
385out:
386	mutex_unlock(&data->mutex);
387
388	iio_trigger_notify_done(indio_dev->trig);
389
390	return IRQ_HANDLED;
391}
392
393static int sx_common_buffer_preenable(struct iio_dev *indio_dev)
394{
395	struct sx_common_data *data = iio_priv(indio_dev);
396	unsigned long channels = 0;
397	int bit, ret;
398
399	mutex_lock(&data->mutex);
400	iio_for_each_active_channel(indio_dev, bit)
401		__set_bit(indio_dev->channels[bit].channel, &channels);
402
403	ret = sx_common_update_chan_en(data, channels, data->chan_event);
404	mutex_unlock(&data->mutex);
405	return ret;
406}
407
408static int sx_common_buffer_postdisable(struct iio_dev *indio_dev)
409{
410	struct sx_common_data *data = iio_priv(indio_dev);
411	int ret;
412
413	mutex_lock(&data->mutex);
414	ret = sx_common_update_chan_en(data, 0, data->chan_event);
415	mutex_unlock(&data->mutex);
416	return ret;
417}
418
419static const struct iio_buffer_setup_ops sx_common_buffer_setup_ops = {
420	.preenable = sx_common_buffer_preenable,
421	.postdisable = sx_common_buffer_postdisable,
422};
423
424#define SX_COMMON_SOFT_RESET				0xde
425
426static int sx_common_init_device(struct device *dev, struct iio_dev *indio_dev)
427{
428	struct sx_common_data *data = iio_priv(indio_dev);
429	struct sx_common_reg_default tmp;
430	const struct sx_common_reg_default *initval;
431	int ret;
432	unsigned int i, val;
433
434	ret = regmap_write(data->regmap, data->chip_info->reg_reset,
435			   SX_COMMON_SOFT_RESET);
436	if (ret)
437		return ret;
438
439	usleep_range(1000, 2000); /* power-up time is ~1ms. */
440
441	/* Clear reset interrupt state by reading SX_COMMON_REG_IRQ_SRC. */
442	ret = regmap_read(data->regmap, SX_COMMON_REG_IRQ_SRC, &val);
443	if (ret)
444		return ret;
445
446	/* Program defaults from constant or BIOS. */
447	for (i = 0; i < data->chip_info->num_default_regs; i++) {
448		initval = data->chip_info->ops.get_default_reg(dev, i, &tmp);
449		ret = regmap_write(data->regmap, initval->reg, initval->def);
450		if (ret)
451			return ret;
452	}
453
454	return data->chip_info->ops.init_compensation(indio_dev);
455}
456
457/**
458 * sx_common_probe() - Common setup for Semtech SAR sensor
459 * @client:		I2C client object
460 * @chip_info:		Semtech sensor chip information.
461 * @regmap_config:	Sensor registers map configuration.
462 */
463int sx_common_probe(struct i2c_client *client,
464		    const struct sx_common_chip_info *chip_info,
465		    const struct regmap_config *regmap_config)
466{
467	static const char * const regulator_names[] = { "vdd", "svdd" };
468	struct device *dev = &client->dev;
469	struct iio_dev *indio_dev;
470	struct sx_common_data *data;
471	int ret;
472
473	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
474	if (!indio_dev)
475		return -ENOMEM;
476
477	data = iio_priv(indio_dev);
478
479	data->chip_info = chip_info;
480	data->client = client;
481	mutex_init(&data->mutex);
482	init_completion(&data->completion);
483
484	data->regmap = devm_regmap_init_i2c(client, regmap_config);
485	if (IS_ERR(data->regmap))
486		return dev_err_probe(dev, PTR_ERR(data->regmap),
487				     "Could init register map\n");
488
489	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
490					     regulator_names);
491	if (ret)
492		return dev_err_probe(dev, ret, "Unable to get regulators\n");
493
494	/* Must wait for Tpor time after initial power up */
495	usleep_range(1000, 1100);
496
497	ret = data->chip_info->ops.check_whoami(dev, indio_dev);
498	if (ret)
499		return dev_err_probe(dev, ret, "error reading WHOAMI\n");
500
501	indio_dev->modes = INDIO_DIRECT_MODE;
502
503	indio_dev->channels =  data->chip_info->iio_channels;
504	indio_dev->num_channels = data->chip_info->num_iio_channels;
505	indio_dev->info = &data->chip_info->iio_info;
506
507	i2c_set_clientdata(client, indio_dev);
508
509	ret = sx_common_init_device(dev, indio_dev);
510	if (ret)
511		return dev_err_probe(dev, ret, "Unable to initialize sensor\n");
512
513	if (client->irq) {
514		ret = devm_request_threaded_irq(dev, client->irq,
515						sx_common_irq_handler,
516						sx_common_irq_thread_handler,
517						IRQF_ONESHOT,
518						"sx_event", indio_dev);
519		if (ret)
520			return dev_err_probe(dev, ret, "No IRQ\n");
521
522		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
523						    indio_dev->name,
524						    iio_device_id(indio_dev));
525		if (!data->trig)
526			return -ENOMEM;
527
528		data->trig->ops = &sx_common_trigger_ops;
529		iio_trigger_set_drvdata(data->trig, indio_dev);
530
531		ret = devm_iio_trigger_register(dev, data->trig);
532		if (ret)
533			return ret;
534	}
535
536	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
537					      iio_pollfunc_store_time,
538					      sx_common_trigger_handler,
539					      &sx_common_buffer_setup_ops);
540	if (ret)
541		return ret;
542
543	return devm_iio_device_register(dev, indio_dev);
544}
545EXPORT_SYMBOL_NS_GPL(sx_common_probe, "SEMTECH_PROX");
546
547MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
548MODULE_DESCRIPTION("Common functions and structures for Semtech sensor");
549MODULE_LICENSE("GPL v2");
~/ Read-only file preview.