File Index
Files and directories
Sign in
FILE

als31300.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/magnetometer/als31300.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Driver for the Allegro MicroSystems ALS31300 3-D Linear Hall Effect Sensor
  4 *
  5 * Copyright (c) 2024 Linaro Limited
  6 */
  7
  8#include <linux/bits.h>
  9#include <linux/bitfield.h>
 10#include <linux/delay.h>
 11#include <linux/module.h>
 12#include <linux/i2c.h>
 13#include <linux/regmap.h>
 14#include <linux/pm.h>
 15#include <linux/pm_runtime.h>
 16#include <linux/regulator/consumer.h>
 17#include <linux/types.h>
 18#include <linux/units.h>
 19
 20#include <linux/iio/buffer.h>
 21#include <linux/iio/iio.h>
 22#include <linux/iio/trigger_consumer.h>
 23#include <linux/iio/triggered_buffer.h>
 24
 25/*
 26 * The Allegro MicroSystems ALS31300 has an EEPROM space to configure how
 27 * the device works and how the interrupt line behaves.
 28 * Only the default setup with external trigger is supported.
 29 *
 30 * While the bindings supports declaring an interrupt line, those
 31 * events are not supported.
 32 *
 33 * It should be possible to adapt the driver to the current
 34 * device EEPROM setup at runtime.
 35 */
 36
 37#define ALS31300_EEPROM_CONFIG		0x02
 38#define ALS31300_EEPROM_INTERRUPT	0x03
 39#define ALS31300_EEPROM_CUSTOMER_1	0x0d
 40#define ALS31300_EEPROM_CUSTOMER_2	0x0e
 41#define ALS31300_EEPROM_CUSTOMER_3	0x0f
 42#define ALS31300_VOL_MODE		0x27
 43#define ALS31300_VOL_MODE_LPDCM			GENMASK(6, 4)
 44#define   ALS31300_LPDCM_INACTIVE_0_5_MS	0
 45#define   ALS31300_LPDCM_INACTIVE_1_0_MS	1
 46#define   ALS31300_LPDCM_INACTIVE_5_0_MS	2
 47#define   ALS31300_LPDCM_INACTIVE_10_0_MS	3
 48#define   ALS31300_LPDCM_INACTIVE_50_0_MS	4
 49#define   ALS31300_LPDCM_INACTIVE_100_0_MS	5
 50#define   ALS31300_LPDCM_INACTIVE_500_0_MS	6
 51#define   ALS31300_LPDCM_INACTIVE_1000_0_MS	7
 52#define ALS31300_VOL_MODE_SLEEP			GENMASK(1, 0)
 53#define   ALS31300_VOL_MODE_ACTIVE_MODE		0
 54#define   ALS31300_VOL_MODE_SLEEP_MODE		1
 55#define   ALS31300_VOL_MODE_LPDCM_MODE		2
 56#define ALS31300_VOL_MSB		0x28
 57#define ALS31300_VOL_MSB_TEMPERATURE		GENMASK(5, 0)
 58#define ALS31300_VOL_MSB_INTERRUPT		BIT(6)
 59#define ALS31300_VOL_MSB_NEW_DATA		BIT(7)
 60#define ALS31300_VOL_MSB_Z_AXIS			GENMASK(15, 8)
 61#define ALS31300_VOL_MSB_Y_AXIS			GENMASK(23, 16)
 62#define ALS31300_VOL_MSB_X_AXIS			GENMASK(31, 24)
 63#define ALS31300_VOL_LSB		0x29
 64#define ALS31300_VOL_LSB_TEMPERATURE		GENMASK(5, 0)
 65#define ALS31300_VOL_LSB_HALL_STATUS		GENMASK(7, 7)
 66#define ALS31300_VOL_LSB_Z_AXIS			GENMASK(11, 8)
 67#define ALS31300_VOL_LSB_Y_AXIS			GENMASK(15, 12)
 68#define ALS31300_VOL_LSB_X_AXIS			GENMASK(19, 16)
 69#define ALS31300_VOL_LSB_INTERRUPT_WRITE	BIT(20)
 70#define ALS31300_CUSTOMER_ACCESS	0x35
 71
 72#define ALS31300_DATA_X_GET(b)		\
 73		sign_extend32(FIELD_GET(ALS31300_VOL_MSB_X_AXIS, b[0]) << 4 | \
 74			      FIELD_GET(ALS31300_VOL_LSB_X_AXIS, b[1]), 11)
 75#define ALS31300_DATA_Y_GET(b)		\
 76		sign_extend32(FIELD_GET(ALS31300_VOL_MSB_Y_AXIS, b[0]) << 4 | \
 77			      FIELD_GET(ALS31300_VOL_LSB_Y_AXIS, b[1]), 11)
 78#define ALS31300_DATA_Z_GET(b)		\
 79		sign_extend32(FIELD_GET(ALS31300_VOL_MSB_Z_AXIS, b[0]) << 4 | \
 80			      FIELD_GET(ALS31300_VOL_LSB_Z_AXIS, b[1]), 11)
 81#define ALS31300_TEMPERATURE_GET(b)	\
 82		(FIELD_GET(ALS31300_VOL_MSB_TEMPERATURE, b[0]) << 6 | \
 83		 FIELD_GET(ALS31300_VOL_LSB_TEMPERATURE, b[1]))
 84
 85enum als31300_channels {
 86	TEMPERATURE = 0,
 87	AXIS_X,
 88	AXIS_Y,
 89	AXIS_Z,
 90};
 91
 92struct als31300_variant_info {
 93	u8 sensitivity;
 94};
 95
 96struct als31300_data {
 97	struct device *dev;
 98	/* protects power on/off the device and access HW */
 99	struct mutex mutex;
100	const struct als31300_variant_info *variant_info;
101	struct regmap *map;
102};
103
104/* The whole measure is split into 2x32-bit registers, we need to read them both at once */
105static int als31300_get_measure(struct als31300_data *data,
106				u16 *t, s16 *x, s16 *y, s16 *z)
107{
108	u32 buf[2];
109	int ret, err;
110
111	guard(mutex)(&data->mutex);
112
113	ret = pm_runtime_resume_and_get(data->dev);
114	if (ret)
115		return ret;
116
117	/*
118	 * Loop until data is valid, new data should have the
119	 * ALS31300_VOL_MSB_NEW_DATA bit set to 1.
120	 * Max update rate is 2KHz, wait up to 1ms.
121	 */
122	ret = read_poll_timeout(regmap_bulk_read, err,
123				err || FIELD_GET(ALS31300_VOL_MSB_NEW_DATA, buf[0]),
124				20, USEC_PER_MSEC, false,
125				data->map, ALS31300_VOL_MSB, buf, ARRAY_SIZE(buf));
126	/* Bail out on read_poll_timeout() error */
127	if (ret)
128		goto out;
129
130	/* Bail out on regmap_bulk_read() error */
131	if (err) {
132		dev_err(data->dev, "read data failed, error %d\n", ret);
133		ret = err;
134		goto out;
135	}
136
137	*t = ALS31300_TEMPERATURE_GET(buf);
138	*x = ALS31300_DATA_X_GET(buf);
139	*y = ALS31300_DATA_Y_GET(buf);
140	*z = ALS31300_DATA_Z_GET(buf);
141
142out:
143	pm_runtime_put_autosuspend(data->dev);
144
145	return ret;
146}
147
148static int als31300_read_raw(struct iio_dev *indio_dev,
149			     const struct iio_chan_spec *chan, int *val,
150			     int *val2, long mask)
151{
152	struct als31300_data *data = iio_priv(indio_dev);
153	s16 x, y, z;
154	u16 t;
155	int ret;
156
157	switch (mask) {
158	case IIO_CHAN_INFO_RAW:
159		ret = als31300_get_measure(data, &t, &x, &y, &z);
160		if (ret)
161			return ret;
162
163		switch (chan->address) {
164		case TEMPERATURE:
165			*val = t;
166			return IIO_VAL_INT;
167		case AXIS_X:
168			*val = x;
169			return IIO_VAL_INT;
170		case AXIS_Y:
171			*val = y;
172			return IIO_VAL_INT;
173		case AXIS_Z:
174			*val = z;
175			return IIO_VAL_INT;
176		default:
177			return -EINVAL;
178		}
179	case IIO_CHAN_INFO_SCALE:
180		switch (chan->type) {
181		case IIO_TEMP:
182			/*
183			 * Fractional part of:
184			 *         1000 * 302 * (value - 1708)
185			 * temp = ----------------------------
186			 *             4096
187			 * to convert temperature in millicelcius.
188			 */
189			*val = MILLI * 302;
190			*val2 = 4096;
191			return IIO_VAL_FRACTIONAL;
192		case IIO_MAGN:
193			/*
194			 * Devices are configured in factory
195			 * with different sensitivities:
196			 * - 500 GAUSS <-> 4 LSB/Gauss
197			 * - 1000 GAUSS <-> 2 LSB/Gauss
198			 * - 2000 GAUSS <-> 1 LSB/Gauss
199			 * with translates by a division of the returned
200			 * value to get Gauss value.
201			 * The sensitivity cannot be read at runtime
202			 * so the value depends on the model compatible
203			 * or device id.
204			 */
205			*val = 1;
206			*val2 = data->variant_info->sensitivity;
207			return IIO_VAL_FRACTIONAL;
208		default:
209			return -EINVAL;
210		}
211	case IIO_CHAN_INFO_OFFSET:
212		switch (chan->type) {
213		case IIO_TEMP:
214			*val = -1708;
215			return IIO_VAL_INT;
216		default:
217			return -EINVAL;
218		}
219	default:
220		return -EINVAL;
221	}
222}
223
224static irqreturn_t als31300_trigger_handler(int irq, void *p)
225{
226	struct iio_poll_func *pf = p;
227	struct iio_dev *indio_dev = pf->indio_dev;
228	struct als31300_data *data = iio_priv(indio_dev);
229	struct {
230		u16 temperature;
231		s16 channels[3];
232		aligned_s64 timestamp;
233	} scan;
234	s16 x, y, z;
235	int ret;
236	u16 t;
237
238	ret = als31300_get_measure(data, &t, &x, &y, &z);
239	if (ret)
240		goto trigger_out;
241
242	scan.temperature = t;
243	scan.channels[0] = x;
244	scan.channels[1] = y;
245	scan.channels[2] = z;
246	iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp);
247
248trigger_out:
249	iio_trigger_notify_done(indio_dev->trig);
250
251	return IRQ_HANDLED;
252}
253
254#define ALS31300_AXIS_CHANNEL(axis, index)				     \
255	{								     \
256		.type = IIO_MAGN,					     \
257		.modified = 1,						     \
258		.channel2 = IIO_MOD_##axis,				     \
259		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		     \
260				      BIT(IIO_CHAN_INFO_SCALE),		     \
261		.address = index,					     \
262		.scan_index = index,					     \
263		.scan_type = {						     \
264			.sign = 's',					     \
265			.realbits = 12,					     \
266			.storagebits = 16,				     \
267			.endianness = IIO_CPU,				     \
268		},							     \
269	}
270
271static const struct iio_chan_spec als31300_channels[] = {
272	{
273		.type = IIO_TEMP,
274		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
275				      BIT(IIO_CHAN_INFO_SCALE) |
276				      BIT(IIO_CHAN_INFO_OFFSET),
277		.address = TEMPERATURE,
278		.scan_index = TEMPERATURE,
279		.scan_type = {
280			.sign = 'u',
281			.realbits = 16,
282			.storagebits = 16,
283			.endianness = IIO_CPU,
284		},
285	},
286	ALS31300_AXIS_CHANNEL(X, AXIS_X),
287	ALS31300_AXIS_CHANNEL(Y, AXIS_Y),
288	ALS31300_AXIS_CHANNEL(Z, AXIS_Z),
289	IIO_CHAN_SOFT_TIMESTAMP(4),
290};
291
292static const struct iio_info als31300_info = {
293	.read_raw = als31300_read_raw,
294};
295
296static int als31300_set_operating_mode(struct als31300_data *data,
297				       unsigned int val)
298{
299	int ret;
300
301	ret = regmap_update_bits(data->map, ALS31300_VOL_MODE,
302				 ALS31300_VOL_MODE_SLEEP, val);
303	if (ret) {
304		dev_err(data->dev, "failed to set operating mode (%pe)\n", ERR_PTR(ret));
305		return ret;
306	}
307
308	/* The time it takes to exit sleep mode is equivalent to Power-On Delay Time */
309	if (val == ALS31300_VOL_MODE_ACTIVE_MODE)
310		fsleep(600);
311
312	return 0;
313}
314
315static void als31300_power_down(void *data)
316{
317	als31300_set_operating_mode(data, ALS31300_VOL_MODE_SLEEP_MODE);
318}
319
320static const struct iio_buffer_setup_ops als31300_setup_ops = {};
321
322static const unsigned long als31300_scan_masks[] = { GENMASK(3, 0), 0 };
323
324static bool als31300_volatile_reg(struct device *dev, unsigned int reg)
325{
326	return reg == ALS31300_VOL_MSB || reg == ALS31300_VOL_LSB;
327}
328
329static const struct regmap_config als31300_regmap_config = {
330	.reg_bits = 8,
331	.val_bits = 32,
332	.max_register = ALS31300_CUSTOMER_ACCESS,
333	.volatile_reg = als31300_volatile_reg,
334};
335
336static int als31300_probe(struct i2c_client *i2c)
337{
338	struct device *dev = &i2c->dev;
339	struct als31300_data *data;
340	struct iio_dev *indio_dev;
341	int ret;
342
343	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
344	if (!indio_dev)
345		return -ENOMEM;
346
347	data = iio_priv(indio_dev);
348	data->dev = dev;
349	i2c_set_clientdata(i2c, indio_dev);
350
351	ret = devm_mutex_init(dev, &data->mutex);
352	if (ret)
353		return ret;
354
355	data->variant_info = i2c_get_match_data(i2c);
356	if (!data->variant_info)
357		return -EINVAL;
358
359	data->map = devm_regmap_init_i2c(i2c, &als31300_regmap_config);
360	if (IS_ERR(data->map))
361		return dev_err_probe(dev, PTR_ERR(data->map),
362				     "failed to allocate register map\n");
363
364	ret = devm_regulator_get_enable(dev, "vcc");
365	if (ret)
366		return dev_err_probe(dev, ret, "failed to enable regulator\n");
367
368	ret = als31300_set_operating_mode(data, ALS31300_VOL_MODE_ACTIVE_MODE);
369	if (ret)
370		return dev_err_probe(dev, ret, "failed to power on device\n");
371
372	ret = devm_add_action_or_reset(dev, als31300_power_down, data);
373	if (ret)
374		return ret;
375
376	indio_dev->info = &als31300_info;
377	indio_dev->modes = INDIO_DIRECT_MODE;
378	indio_dev->name = i2c->name;
379	indio_dev->channels = als31300_channels;
380	indio_dev->num_channels = ARRAY_SIZE(als31300_channels);
381	indio_dev->available_scan_masks = als31300_scan_masks;
382
383	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
384					      iio_pollfunc_store_time,
385					      als31300_trigger_handler,
386					      &als31300_setup_ops);
387	if (ret < 0)
388		return dev_err_probe(dev, ret, "iio triggered buffer setup failed\n");
389
390	ret = pm_runtime_set_active(dev);
391	if (ret < 0)
392		return ret;
393
394	ret = devm_pm_runtime_enable(dev);
395	if (ret)
396		return ret;
397
398	pm_runtime_get_noresume(dev);
399	pm_runtime_set_autosuspend_delay(dev, 200);
400	pm_runtime_use_autosuspend(dev);
401
402	pm_runtime_put_autosuspend(dev);
403
404	ret = devm_iio_device_register(dev, indio_dev);
405	if (ret)
406		return dev_err_probe(dev, ret, "device register failed\n");
407
408	return 0;
409}
410
411static int als31300_runtime_suspend(struct device *dev)
412{
413	struct iio_dev *indio_dev = dev_get_drvdata(dev);
414	struct als31300_data *data = iio_priv(indio_dev);
415
416	return als31300_set_operating_mode(data, ALS31300_VOL_MODE_SLEEP_MODE);
417}
418
419static int als31300_runtime_resume(struct device *dev)
420{
421	struct iio_dev *indio_dev = dev_get_drvdata(dev);
422	struct als31300_data *data = iio_priv(indio_dev);
423
424	return als31300_set_operating_mode(data, ALS31300_VOL_MODE_ACTIVE_MODE);
425}
426
427static DEFINE_RUNTIME_DEV_PM_OPS(als31300_pm_ops,
428				 als31300_runtime_suspend, als31300_runtime_resume,
429				 NULL);
430
431static const struct als31300_variant_info al31300_variant_500 = {
432	.sensitivity = 4,
433};
434
435static const struct als31300_variant_info al31300_variant_1000 = {
436	.sensitivity = 2,
437};
438
439static const struct als31300_variant_info al31300_variant_2000 = {
440	.sensitivity = 1,
441};
442
443static const struct i2c_device_id als31300_id[] = {
444	{
445		.name = "als31300-500",
446		.driver_data = (kernel_ulong_t)&al31300_variant_500,
447	},
448	{
449		.name = "als31300-1000",
450		.driver_data = (kernel_ulong_t)&al31300_variant_1000,
451	},
452	{
453		.name = "als31300-2000",
454		.driver_data = (kernel_ulong_t)&al31300_variant_2000,
455	},
456	{ }
457};
458MODULE_DEVICE_TABLE(i2c, als31300_id);
459
460static const struct of_device_id als31300_of_match[] = {
461	{
462		.compatible = "allegromicro,als31300-500",
463		.data = &al31300_variant_500,
464	},
465	{
466		.compatible = "allegromicro,als31300-1000",
467		.data = &al31300_variant_1000,
468	},
469	{
470		.compatible = "allegromicro,als31300-2000",
471		.data = &al31300_variant_2000,
472	},
473	{ }
474};
475MODULE_DEVICE_TABLE(of, als31300_of_match);
476
477static struct i2c_driver als31300_driver = {
478	.driver	 = {
479		.name = "als31300",
480		.of_match_table = als31300_of_match,
481		.pm = pm_ptr(&als31300_pm_ops),
482	},
483	.probe = als31300_probe,
484	.id_table = als31300_id,
485};
486module_i2c_driver(als31300_driver);
487
488MODULE_LICENSE("GPL");
489MODULE_DESCRIPTION("ALS31300 3-D Linear Hall Effect Driver");
490MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
~/ Read-only file preview.