brintos

brintos / linux-shallow public Read only

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