File Index
Files and directories
Sign in
FILE

hi8435.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/adc/hi8435.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Holt Integrated Circuits HI-8435 threshold detector driver
  4 *
  5 * Copyright (C) 2015 Zodiac Inflight Innovations
  6 * Copyright (C) 2015 Cogent Embedded, Inc.
  7 */
  8
  9#include <linux/delay.h>
 10#include <linux/iio/events.h>
 11#include <linux/iio/iio.h>
 12#include <linux/iio/sysfs.h>
 13#include <linux/iio/trigger.h>
 14#include <linux/iio/trigger_consumer.h>
 15#include <linux/iio/triggered_event.h>
 16#include <linux/interrupt.h>
 17#include <linux/module.h>
 18#include <linux/mod_devicetable.h>
 19#include <linux/spi/spi.h>
 20#include <linux/gpio/consumer.h>
 21
 22/* Register offsets for HI-8435 */
 23#define HI8435_CTRL_REG		0x02
 24#define HI8435_PSEN_REG		0x04
 25#define HI8435_TMDATA_REG	0x1E
 26#define HI8435_GOCENHYS_REG	0x3A
 27#define HI8435_SOCENHYS_REG	0x3C
 28#define HI8435_SO7_0_REG	0x10
 29#define HI8435_SO15_8_REG	0x12
 30#define HI8435_SO23_16_REG	0x14
 31#define HI8435_SO31_24_REG	0x16
 32#define HI8435_SO31_0_REG	0x78
 33
 34#define HI8435_WRITE_OPCODE	0x00
 35#define HI8435_READ_OPCODE	0x80
 36
 37/* CTRL register bits */
 38#define HI8435_CTRL_TEST	0x01
 39#define HI8435_CTRL_SRST	0x02
 40
 41struct hi8435_priv {
 42	struct spi_device *spi;
 43	struct mutex lock;
 44
 45	unsigned long event_scan_mask; /* soft mask/unmask channels events */
 46	unsigned int event_prev_val;
 47
 48	unsigned threshold_lo[2]; /* GND-Open and Supply-Open thresholds */
 49	unsigned threshold_hi[2]; /* GND-Open and Supply-Open thresholds */
 50	u8 reg_buffer[3] __aligned(IIO_DMA_MINALIGN);
 51};
 52
 53static int hi8435_readb(struct hi8435_priv *priv, u8 reg, u8 *val)
 54{
 55	reg |= HI8435_READ_OPCODE;
 56	return spi_write_then_read(priv->spi, &reg, 1, val, 1);
 57}
 58
 59static int hi8435_readw(struct hi8435_priv *priv, u8 reg, u16 *val)
 60{
 61	int ret;
 62	__be16 be_val;
 63
 64	reg |= HI8435_READ_OPCODE;
 65	ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 2);
 66	*val = be16_to_cpu(be_val);
 67
 68	return ret;
 69}
 70
 71static int hi8435_readl(struct hi8435_priv *priv, u8 reg, u32 *val)
 72{
 73	int ret;
 74	__be32 be_val;
 75
 76	reg |= HI8435_READ_OPCODE;
 77	ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 4);
 78	*val = be32_to_cpu(be_val);
 79
 80	return ret;
 81}
 82
 83static int hi8435_writeb(struct hi8435_priv *priv, u8 reg, u8 val)
 84{
 85	priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
 86	priv->reg_buffer[1] = val;
 87
 88	return spi_write(priv->spi, priv->reg_buffer, 2);
 89}
 90
 91static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val)
 92{
 93	priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
 94	priv->reg_buffer[1] = (val >> 8) & 0xff;
 95	priv->reg_buffer[2] = val & 0xff;
 96
 97	return spi_write(priv->spi, priv->reg_buffer, 3);
 98}
 99
100static int hi8435_read_raw(struct iio_dev *idev,
101			   const struct iio_chan_spec *chan,
102			   int *val, int *val2, long mask)
103{
104	struct hi8435_priv *priv = iio_priv(idev);
105	u32 tmp;
106	int ret;
107
108	switch (mask) {
109	case IIO_CHAN_INFO_RAW:
110		ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
111		if (ret < 0)
112			return ret;
113		*val = !!(tmp & BIT(chan->channel));
114		return IIO_VAL_INT;
115	default:
116		return -EINVAL;
117	}
118}
119
120static int hi8435_read_event_config(struct iio_dev *idev,
121				    const struct iio_chan_spec *chan,
122				    enum iio_event_type type,
123				    enum iio_event_direction dir)
124{
125	struct hi8435_priv *priv = iio_priv(idev);
126
127	return !!(priv->event_scan_mask & BIT(chan->channel));
128}
129
130static int hi8435_write_event_config(struct iio_dev *idev,
131				     const struct iio_chan_spec *chan,
132				     enum iio_event_type type,
133				     enum iio_event_direction dir, bool state)
134{
135	struct hi8435_priv *priv = iio_priv(idev);
136	int ret;
137	u32 tmp;
138
139	if (state) {
140		ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
141		if (ret < 0)
142			return ret;
143		if (tmp & BIT(chan->channel))
144			priv->event_prev_val |= BIT(chan->channel);
145		else
146			priv->event_prev_val &= ~BIT(chan->channel);
147
148		priv->event_scan_mask |= BIT(chan->channel);
149	} else
150		priv->event_scan_mask &= ~BIT(chan->channel);
151
152	return 0;
153}
154
155static int hi8435_read_event_value(struct iio_dev *idev,
156				   const struct iio_chan_spec *chan,
157				   enum iio_event_type type,
158				   enum iio_event_direction dir,
159				   enum iio_event_info info,
160				   int *val, int *val2)
161{
162	struct hi8435_priv *priv = iio_priv(idev);
163	int ret;
164	u8 mode, psen;
165	u16 reg;
166
167	ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
168	if (ret < 0)
169		return ret;
170
171	/* Supply-Open or GND-Open sensing mode */
172	mode = !!(psen & BIT(chan->channel / 8));
173
174	ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
175				 HI8435_GOCENHYS_REG, &reg);
176	if (ret < 0)
177		return ret;
178
179	if (dir == IIO_EV_DIR_FALLING)
180		*val = ((reg & 0xff) - (reg >> 8)) / 2;
181	else if (dir == IIO_EV_DIR_RISING)
182		*val = ((reg & 0xff) + (reg >> 8)) / 2;
183
184	return IIO_VAL_INT;
185}
186
187static int hi8435_write_event_value(struct iio_dev *idev,
188				    const struct iio_chan_spec *chan,
189				    enum iio_event_type type,
190				    enum iio_event_direction dir,
191				    enum iio_event_info info,
192				    int val, int val2)
193{
194	struct hi8435_priv *priv = iio_priv(idev);
195	int ret;
196	u8 mode, psen;
197	u16 reg;
198
199	ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
200	if (ret < 0)
201		return ret;
202
203	/* Supply-Open or GND-Open sensing mode */
204	mode = !!(psen & BIT(chan->channel / 8));
205
206	ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
207				 HI8435_GOCENHYS_REG, &reg);
208	if (ret < 0)
209		return ret;
210
211	if (dir == IIO_EV_DIR_FALLING) {
212		/* falling threshold range 2..21V, hysteresis minimum 2V */
213		if (val < 2 || val > 21 || (val + 2) > priv->threshold_hi[mode])
214			return -EINVAL;
215
216		if (val == priv->threshold_lo[mode])
217			return 0;
218
219		priv->threshold_lo[mode] = val;
220
221		/* hysteresis must not be odd */
222		if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
223			priv->threshold_hi[mode]--;
224	} else if (dir == IIO_EV_DIR_RISING) {
225		/* rising threshold range 3..22V, hysteresis minimum 2V */
226		if (val < 3 || val > 22 || val < (priv->threshold_lo[mode] + 2))
227			return -EINVAL;
228
229		if (val == priv->threshold_hi[mode])
230			return 0;
231
232		priv->threshold_hi[mode] = val;
233
234		/* hysteresis must not be odd */
235		if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
236			priv->threshold_lo[mode]++;
237	}
238
239	/* program thresholds */
240	mutex_lock(&priv->lock);
241
242	ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
243				 HI8435_GOCENHYS_REG, &reg);
244	if (ret < 0) {
245		mutex_unlock(&priv->lock);
246		return ret;
247	}
248
249	/* hysteresis */
250	reg = priv->threshold_hi[mode] - priv->threshold_lo[mode];
251	reg <<= 8;
252	/* threshold center */
253	reg |= (priv->threshold_hi[mode] + priv->threshold_lo[mode]);
254
255	ret = hi8435_writew(priv, mode ? HI8435_SOCENHYS_REG :
256				  HI8435_GOCENHYS_REG, reg);
257
258	mutex_unlock(&priv->lock);
259
260	return ret;
261}
262
263static int hi8435_debugfs_reg_access(struct iio_dev *idev,
264				     unsigned reg, unsigned writeval,
265				     unsigned *readval)
266{
267	struct hi8435_priv *priv = iio_priv(idev);
268	int ret;
269	u8 val;
270
271	if (readval != NULL) {
272		ret = hi8435_readb(priv, reg, &val);
273		*readval = val;
274	} else {
275		val = (u8)writeval;
276		ret = hi8435_writeb(priv, reg, val);
277	}
278
279	return ret;
280}
281
282static const struct iio_event_spec hi8435_events[] = {
283	{
284		.type = IIO_EV_TYPE_THRESH,
285		.dir = IIO_EV_DIR_RISING,
286		.mask_separate = BIT(IIO_EV_INFO_VALUE),
287	}, {
288		.type = IIO_EV_TYPE_THRESH,
289		.dir = IIO_EV_DIR_FALLING,
290		.mask_separate = BIT(IIO_EV_INFO_VALUE),
291	}, {
292		.type = IIO_EV_TYPE_THRESH,
293		.dir = IIO_EV_DIR_EITHER,
294		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
295	},
296};
297
298static int hi8435_get_sensing_mode(struct iio_dev *idev,
299				   const struct iio_chan_spec *chan)
300{
301	struct hi8435_priv *priv = iio_priv(idev);
302	int ret;
303	u8 reg;
304
305	ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
306	if (ret < 0)
307		return ret;
308
309	return !!(reg & BIT(chan->channel / 8));
310}
311
312static int hi8435_set_sensing_mode(struct iio_dev *idev,
313				   const struct iio_chan_spec *chan,
314				   unsigned int mode)
315{
316	struct hi8435_priv *priv = iio_priv(idev);
317	int ret;
318	u8 reg;
319
320	mutex_lock(&priv->lock);
321
322	ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
323	if (ret < 0) {
324		mutex_unlock(&priv->lock);
325		return ret;
326	}
327
328	reg &= ~BIT(chan->channel / 8);
329	if (mode)
330		reg |= BIT(chan->channel / 8);
331
332	ret = hi8435_writeb(priv, HI8435_PSEN_REG, reg);
333
334	mutex_unlock(&priv->lock);
335
336	return ret;
337}
338
339static const char * const hi8435_sensing_modes[] = { "GND-Open",
340						     "Supply-Open" };
341
342static const struct iio_enum hi8435_sensing_mode = {
343	.items = hi8435_sensing_modes,
344	.num_items = ARRAY_SIZE(hi8435_sensing_modes),
345	.get = hi8435_get_sensing_mode,
346	.set = hi8435_set_sensing_mode,
347};
348
349static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
350	IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode),
351	IIO_ENUM_AVAILABLE("sensing_mode", IIO_SHARED_BY_TYPE, &hi8435_sensing_mode),
352	{ }
353};
354
355#define HI8435_VOLTAGE_CHANNEL(num)			\
356{							\
357	.type = IIO_VOLTAGE,				\
358	.indexed = 1,					\
359	.channel = num,					\
360	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
361	.event_spec = hi8435_events,			\
362	.num_event_specs = ARRAY_SIZE(hi8435_events),	\
363	.ext_info = hi8435_ext_info,			\
364}
365
366static const struct iio_chan_spec hi8435_channels[] = {
367	HI8435_VOLTAGE_CHANNEL(0),
368	HI8435_VOLTAGE_CHANNEL(1),
369	HI8435_VOLTAGE_CHANNEL(2),
370	HI8435_VOLTAGE_CHANNEL(3),
371	HI8435_VOLTAGE_CHANNEL(4),
372	HI8435_VOLTAGE_CHANNEL(5),
373	HI8435_VOLTAGE_CHANNEL(6),
374	HI8435_VOLTAGE_CHANNEL(7),
375	HI8435_VOLTAGE_CHANNEL(8),
376	HI8435_VOLTAGE_CHANNEL(9),
377	HI8435_VOLTAGE_CHANNEL(10),
378	HI8435_VOLTAGE_CHANNEL(11),
379	HI8435_VOLTAGE_CHANNEL(12),
380	HI8435_VOLTAGE_CHANNEL(13),
381	HI8435_VOLTAGE_CHANNEL(14),
382	HI8435_VOLTAGE_CHANNEL(15),
383	HI8435_VOLTAGE_CHANNEL(16),
384	HI8435_VOLTAGE_CHANNEL(17),
385	HI8435_VOLTAGE_CHANNEL(18),
386	HI8435_VOLTAGE_CHANNEL(19),
387	HI8435_VOLTAGE_CHANNEL(20),
388	HI8435_VOLTAGE_CHANNEL(21),
389	HI8435_VOLTAGE_CHANNEL(22),
390	HI8435_VOLTAGE_CHANNEL(23),
391	HI8435_VOLTAGE_CHANNEL(24),
392	HI8435_VOLTAGE_CHANNEL(25),
393	HI8435_VOLTAGE_CHANNEL(26),
394	HI8435_VOLTAGE_CHANNEL(27),
395	HI8435_VOLTAGE_CHANNEL(28),
396	HI8435_VOLTAGE_CHANNEL(29),
397	HI8435_VOLTAGE_CHANNEL(30),
398	HI8435_VOLTAGE_CHANNEL(31),
399	IIO_CHAN_SOFT_TIMESTAMP(32),
400};
401
402static const struct iio_info hi8435_info = {
403	.read_raw = hi8435_read_raw,
404	.read_event_config = hi8435_read_event_config,
405	.write_event_config = hi8435_write_event_config,
406	.read_event_value = hi8435_read_event_value,
407	.write_event_value = hi8435_write_event_value,
408	.debugfs_reg_access = hi8435_debugfs_reg_access,
409};
410
411static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val)
412{
413	struct hi8435_priv *priv = iio_priv(idev);
414	enum iio_event_direction dir;
415	unsigned int i;
416	unsigned int status = priv->event_prev_val ^ val;
417
418	if (!status)
419		return;
420
421	for_each_set_bit(i, &priv->event_scan_mask, 32) {
422		if (status & BIT(i)) {
423			dir = val & BIT(i) ? IIO_EV_DIR_RISING :
424					     IIO_EV_DIR_FALLING;
425			iio_push_event(idev,
426				       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
427						    IIO_EV_TYPE_THRESH, dir),
428				       iio_get_time_ns(idev));
429		}
430	}
431
432	priv->event_prev_val = val;
433}
434
435static irqreturn_t hi8435_trigger_handler(int irq, void *private)
436{
437	struct iio_poll_func *pf = private;
438	struct iio_dev *idev = pf->indio_dev;
439	struct hi8435_priv *priv = iio_priv(idev);
440	u32 val;
441	int ret;
442
443	ret = hi8435_readl(priv, HI8435_SO31_0_REG, &val);
444	if (ret < 0)
445		goto err_read;
446
447	hi8435_iio_push_event(idev, val);
448
449err_read:
450	iio_trigger_notify_done(idev->trig);
451
452	return IRQ_HANDLED;
453}
454
455static void hi8435_triggered_event_cleanup(void *data)
456{
457	iio_triggered_event_cleanup(data);
458}
459
460static int hi8435_probe(struct spi_device *spi)
461{
462	struct iio_dev *idev;
463	struct hi8435_priv *priv;
464	struct gpio_desc *reset_gpio;
465	int ret;
466
467	idev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
468	if (!idev)
469		return -ENOMEM;
470
471	priv = iio_priv(idev);
472	priv->spi = spi;
473
474	reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
475	if (IS_ERR(reset_gpio)) {
476		/* chip s/w reset if h/w reset failed */
477		hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
478		hi8435_writeb(priv, HI8435_CTRL_REG, 0);
479	} else {
480		udelay(5);
481		gpiod_set_value_cansleep(reset_gpio, 1);
482	}
483
484	mutex_init(&priv->lock);
485
486	idev->name		= spi_get_device_id(spi)->name;
487	idev->modes		= INDIO_DIRECT_MODE;
488	idev->info		= &hi8435_info;
489	idev->channels		= hi8435_channels;
490	idev->num_channels	= ARRAY_SIZE(hi8435_channels);
491
492	/* unmask all events */
493	priv->event_scan_mask = ~(0);
494	/*
495	 * There is a restriction in the chip - the hysteresis can not be odd.
496	 * If the hysteresis is set to odd value then chip gets into lock state
497	 * and not functional anymore.
498	 * After chip reset the thresholds are in undefined state, so we need to
499	 * initialize thresholds to some initial values and then prevent
500	 * userspace setting odd hysteresis.
501	 *
502	 * Set threshold low voltage to 2V, threshold high voltage to 4V
503	 * for both GND-Open and Supply-Open sensing modes.
504	 */
505	priv->threshold_lo[0] = priv->threshold_lo[1] = 2;
506	priv->threshold_hi[0] = priv->threshold_hi[1] = 4;
507	hi8435_writew(priv, HI8435_GOCENHYS_REG, 0x206);
508	hi8435_writew(priv, HI8435_SOCENHYS_REG, 0x206);
509
510	ret = iio_triggered_event_setup(idev, NULL, hi8435_trigger_handler);
511	if (ret)
512		return ret;
513
514	ret = devm_add_action_or_reset(&spi->dev,
515				       hi8435_triggered_event_cleanup,
516				       idev);
517	if (ret)
518		return ret;
519
520	return devm_iio_device_register(&spi->dev, idev);
521}
522
523static const struct of_device_id hi8435_dt_ids[] = {
524	{ .compatible = "holt,hi8435" },
525	{ }
526};
527MODULE_DEVICE_TABLE(of, hi8435_dt_ids);
528
529static const struct spi_device_id hi8435_id[] = {
530	{ "hi8435", 0 },
531	{ }
532};
533MODULE_DEVICE_TABLE(spi, hi8435_id);
534
535static struct spi_driver hi8435_driver = {
536	.driver	= {
537		.name		= "hi8435",
538		.of_match_table	= hi8435_dt_ids,
539	},
540	.probe		= hi8435_probe,
541	.id_table	= hi8435_id,
542};
543module_spi_driver(hi8435_driver);
544
545MODULE_LICENSE("GPL");
546MODULE_AUTHOR("Vladimir Barinov");
547MODULE_DESCRIPTION("HI-8435 threshold detector");
~/ Read-only file preview.