diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-10-20 07:54:15 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-10-20 07:54:15 +0200 |
commit | b4b6cc10c6c8b665cea241835b0ae52d224b8657 (patch) | |
tree | fd53735805ade46c24f13f2e2832079c788206fb /drivers/iio | |
parent | f7572e93d5f6bc4f659d2a9b603574cd126482d8 (diff) | |
parent | 89a1d2f064d2ae77a9cd6a8c7ac42b3c1647efa5 (diff) | |
download | linux-b4b6cc10c6c8b665cea241835b0ae52d224b8657.tar.gz linux-b4b6cc10c6c8b665cea241835b0ae52d224b8657.tar.bz2 linux-b4b6cc10c6c8b665cea241835b0ae52d224b8657.zip |
Merge tag 'iio-for-6.7a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes:
IIO: 1st set of new device support, features and cleanup for 6.7
Particularly great to see a resolver driver move out of staging via a
massive set of changes. Only took 13 years :)
One small patch added then reverted due to a report of test breakage
(ashai-kasei,ak8975: Drop deprecated enums.)
An immutable branch was used for some hid-senors changes in case
there was a need to take them into the HID tree as well.
New device support
-----------------
adi,hmc425a
- Add support for HMC540SLP3E broadband 4-bit digital attenuator.
kionix,kx022a
- Add support for the kx132-1211 accelerometer. Require significant
driver rework to enable this including add a chip type specific
structure to deal with the chip differences.
- Add support for the kx132acr-lbz accelerometer (subset of the kx022a
feature set).
lltc,ltc2309
- New driver for this 8 channel ADC.
microchip,mcp3911
- Add support for rest of mcp391x family of ADCs (there are various
differences beyond simple channel count variation.
Series includes some general driver cleanup.
microchip,mcp3564
- New driver for MCP3461, MCP3462, MCP3464, MCP3541, MCP3562, MCP3564
and their R variants of 16/24bit ADCs. A few minor fixed followed.
rohm,bu1390
- New driver for this pressure sensor.
Staging graduation
------------------
adi,ad1210 (after 13 or so years :)
- More or less a complete (step-wise) rewrite of this resolver driver
to bring it up to date with modern IIO standards. The fault signal
handling mapping to event channels was particularly complex and
significant part of the changes.
Features
--------
iio-core
- Add chromacity and color temperature channel types.
adi,ad7192
- Oversampling ratio control (called fast settling in datasheet).
adi,adis16475
- Add core support and then driver support for delta angle and delta
velocity channels. These are intended for summation to establish
angle and velocity changes over larger timescales. Fix was
needed for alignment after the temperature channel. Further fix
reduced set of devices for which the buffer support was applicable
as seems burst reads don't cover these on all devices.
hid-sensors-als
- Chromacity and color temperatures support including in amd sfh.
stx104
- Add support for counter subsystem to this multipurpose device.
ti,twl6030
- Add missing device tree binding description.
Clean up and minor fixes.
------------------------
treewide
- Drop some unused declarations across IIO.
- Make more use of device_get_match_data() instead of OF specific
approaches.
Similar cleanup to sets of drivers.
- Stop platform remove callbacks returning anything by using the
temporary remove_new() callback.
- Use i2c_get_match_data() to cope nicely with all types of ID table
entry.
- Use device_get_match_data() for various platform device to cope
with more types of firmware.
- Convert from enum to pointer in ID tables allowing use of
i2c_get_match_data().
- Fix sorting on some ID tables.
- Include specific string helper headers rather than simply string_helpers.h
docs
- Better description of the ordering requirements etc for
available_scan_masks.
tools
- Handle alignment of mixed sizes where the last element isn't the biggest
correctly. Seems that doesn't happen often!
adi,ad2s1210
- Lots of work from David Lechner on this driver including a few fixes
that are going with the rework to avoid slowing that down.
adi,ad4310
- Replace deprecated devm_clk_register()
adi,ad74413r
- Bring the channel function setting inline with the datasheet.
adi,ad7192
- Change to FIELD_PREP(), FIELD_GET().
- Calculate f_order from the sinc filter and chop filter states.
- Move more per chip config into data in struct ad7192_chip_info
- Cleanup unused parameter in channel macros.
adi,adf4350
- Make use of devm_* to simplify error handling for many of the setup
calls in probe() / tear down in remove() and error paths. Some more
work to be done on this one.
- Use dev_err_probe() for errors in probe() callback.
adi,adf4413
- Typo in function name prefix.
adi,adxl345
- Add channel scale to the chip type specific structure and drop
using a type field previously used for indirection.
asahi,ak8985
- Fix a mismatch introduced when switching from enum->pointers
in the match tables.
amlogic,meson
- Expand error logging during probe.
invensense,mpu6050
- Support level-shifter control. Whilst no one is sure exactly what this
is doing it is needed for some old boards.
- Document mount-matrix dt-binding.
mediatek,mt6577
- Use devm_clk_get_enabled() to replace open coded version and move
everything over to being device managed. Drop now empty remove()
callback. Fix follows to put the drvdata back.
- Use dev_err_probe() for error reporting in probe() callback.
memsic,mxc4005
- Add of_match_table.
microchip,mcp4725
- Move various chip specific data from being looked up by chip ID to
data in the chip type specific structure.
silicon-labs,si7005
- Add of_match_table and entry in trivial-devices.yaml
st,lsm6dsx
- Add missing mount-matrix dt binding documentation.
st,spear
- Use devm_clk_get_enabled() and some other devm calls to move everything
over to being device managed. Drop now empty remove() callback.
- Use dev_err_probe() to better handled deferred probing and tidy up
error reporting in probe() callback.
st,stm32-adc
- Add a bit of additional checking in probe() to protect against a NULL
pointer (no known path to trigger it today).
- Replace deprecated strncpy()
ti,ads1015
- Allow for edge triggers.
- Document interrupt in dt-bindings.
* tag 'iio-for-6.7a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (201 commits)
iio: Use device_get_match_data()
iio: adc: MCP3564: fix warn: unsigned '__x' is never less than zero.
dt-bindings: trivial-devices: add silabs,si7005
iio: si7005: Add device tree support
drivers: imu: adis16475.c: Remove scan index from delta channels
dt-bindings: iio: imu: st,lsm6dsx: add mount-matrix property
iio: resolver: ad2s1210: remove of_match_ptr()
iio: resolver: ad2s1210: remove DRV_NAME macro
iio: resolver: ad2s1210: move out of staging
staging: iio: resolver: ad2s1210: simplify code with guard(mutex)
staging: iio: resolver: ad2s1210: clear faults after soft reset
staging: iio: resolver: ad2s1210: refactor sample toggle
staging: iio: resolver: ad2s1210: remove fault attribute
staging: iio: resolver: ad2s1210: add label attribute support
staging: iio: resolver: ad2s1210: add register/fault support summary
staging: iio: resolver: ad2s1210: implement fault events
iio: event: add optional event label support
staging: iio: resolver: ad2s1210: rename DOS reset min/max attrs
staging: iio: resolver: ad2s1210: convert DOS mismatch threshold to event attr
staging: iio: resolver: ad2s1210: convert DOS overrange threshold to event attr
...
Diffstat (limited to 'drivers/iio')
111 files changed, 6406 insertions, 1183 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index b6b45d359f28..f113dae59048 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -418,8 +418,9 @@ config IIO_KX022A_SPI select IIO_KX022A select REGMAP_SPI help - Enable support for the Kionix KX022A digital tri-axis - accelerometer connected to I2C interface. + Enable support for the Kionix digital tri-axis accelerometers + connected to SPI interface. Supported devices are: + KX022A, KX132-1211, KX132ACR-LBZ config IIO_KX022A_I2C tristate "Kionix KX022A tri-axis digital accelerometer I2C interface" @@ -427,8 +428,9 @@ config IIO_KX022A_I2C select IIO_KX022A select REGMAP_I2C help - Enable support for the Kionix KX022A digital tri-axis - accelerometer connected to I2C interface. + Enable support for the Kionix digital tri-axis accelerometers + connected to I2C interface. Supported devices are: + KX022A, KX132-1211, KX132ACR-LBZ config KXSD9 tristate "Kionix KXSD9 Accelerometer Driver" diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h index d7e67cb08538..284bd387ce69 100644 --- a/drivers/iio/accel/adxl345.h +++ b/drivers/iio/accel/adxl345.h @@ -8,9 +8,24 @@ #ifndef _ADXL345_H_ #define _ADXL345_H_ -enum adxl345_device_type { - ADXL345 = 1, - ADXL375 = 2, +/* + * In full-resolution mode, scale factor is maintained at ~4 mg/LSB + * in all g ranges. + * + * At +/- 16g with 13-bit resolution, scale is computed as: + * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383 + */ +#define ADXL345_USCALE 38300 + +/* + * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's + * ~480mm/s**2 per LSB. + */ +#define ADXL375_USCALE 480000 + +struct adxl345_chip_info { + const char *name; + int uscale; }; int adxl345_core_probe(struct device *dev, struct regmap *regmap); diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 1919e0089c11..8bd30a23ed3b 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -45,25 +45,10 @@ #define ADXL345_DEVID 0xE5 -/* - * In full-resolution mode, scale factor is maintained at ~4 mg/LSB - * in all g ranges. - * - * At +/- 16g with 13-bit resolution, scale is computed as: - * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383 - */ -static const int adxl345_uscale = 38300; - -/* - * The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's - * ~480mm/s**2 per LSB. - */ -static const int adxl375_uscale = 480000; - struct adxl345_data { + const struct adxl345_chip_info *info; struct regmap *regmap; u8 data_range; - enum adxl345_device_type type; }; #define ADXL345_CHANNEL(index, axis) { \ @@ -110,15 +95,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - switch (data->type) { - case ADXL345: - *val2 = adxl345_uscale; - break; - case ADXL375: - *val2 = adxl375_uscale; - break; - } - + *val2 = data->info->uscale; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS: ret = regmap_read(data->regmap, @@ -222,25 +199,11 @@ static void adxl345_powerdown(void *regmap) int adxl345_core_probe(struct device *dev, struct regmap *regmap) { - enum adxl345_device_type type; struct adxl345_data *data; struct iio_dev *indio_dev; - const char *name; u32 regval; int ret; - type = (uintptr_t)device_get_match_data(dev); - switch (type) { - case ADXL345: - name = "adxl345"; - break; - case ADXL375: - name = "adxl375"; - break; - default: - return -EINVAL; - } - ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); if (ret < 0) return dev_err_probe(dev, ret, "Error reading device ID\n"); @@ -255,16 +218,18 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap) data = iio_priv(indio_dev); data->regmap = regmap; - data->type = type; /* Enable full-resolution mode */ data->data_range = ADXL345_DATA_FORMAT_FULL_RES; + data->info = device_get_match_data(dev); + if (!data->info) + return -ENODEV; ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, data->data_range); if (ret < 0) return dev_err_probe(dev, ret, "Failed to set data range\n"); - indio_dev->name = name; + indio_dev->name = data->info->name; indio_dev->info = &adxl345_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = adxl345_channels; diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index e47d12f19602..a3084b0a8f78 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -30,22 +30,32 @@ static int adxl345_i2c_probe(struct i2c_client *client) return adxl345_core_probe(&client->dev, regmap); } +static const struct adxl345_chip_info adxl345_i2c_info = { + .name = "adxl345", + .uscale = ADXL345_USCALE, +}; + +static const struct adxl345_chip_info adxl375_i2c_info = { + .name = "adxl375", + .uscale = ADXL375_USCALE, +}; + static const struct i2c_device_id adxl345_i2c_id[] = { - { "adxl345", ADXL345 }, - { "adxl375", ADXL375 }, + { "adxl345", (kernel_ulong_t)&adxl345_i2c_info }, + { "adxl375", (kernel_ulong_t)&adxl375_i2c_info }, { } }; MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); static const struct of_device_id adxl345_of_match[] = { - { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, - { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, + { .compatible = "adi,adxl345", .data = &adxl345_i2c_info }, + { .compatible = "adi,adxl375", .data = &adxl375_i2c_info }, { } }; MODULE_DEVICE_TABLE(of, adxl345_of_match); static const struct acpi_device_id adxl345_acpi_match[] = { - { "ADS0345", ADXL345 }, + { "ADS0345", (kernel_ulong_t)&adxl345_i2c_info }, { } }; MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index aaade5808657..93ca349f1780 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -36,22 +36,32 @@ static int adxl345_spi_probe(struct spi_device *spi) return adxl345_core_probe(&spi->dev, regmap); } +static const struct adxl345_chip_info adxl345_spi_info = { + .name = "adxl345", + .uscale = ADXL345_USCALE, +}; + +static const struct adxl345_chip_info adxl375_spi_info = { + .name = "adxl375", + .uscale = ADXL375_USCALE, +}; + static const struct spi_device_id adxl345_spi_id[] = { - { "adxl345", ADXL345 }, - { "adxl375", ADXL375 }, + { "adxl345", (kernel_ulong_t)&adxl345_spi_info }, + { "adxl375", (kernel_ulong_t)&adxl375_spi_info }, { } }; MODULE_DEVICE_TABLE(spi, adxl345_spi_id); static const struct of_device_id adxl345_of_match[] = { - { .compatible = "adi,adxl345", .data = (const void *)ADXL345 }, - { .compatible = "adi,adxl375", .data = (const void *)ADXL375 }, + { .compatible = "adi,adxl345", .data = &adxl345_spi_info }, + { .compatible = "adi,adxl375", .data = &adxl375_spi_info }, { } }; MODULE_DEVICE_TABLE(of, adxl345_of_match); static const struct acpi_device_id adxl345_acpi_match[] = { - { "ADS0345", ADXL345 }, + { "ADS0345", (kernel_ulong_t)&adxl345_spi_info }, { } }; MODULE_DEVICE_TABLE(acpi, adxl345_acpi_match); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 13439f52d26d..ab4fccb24b6c 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -926,7 +926,6 @@ static int bma180_probe(struct i2c_client *client) struct device *dev = &client->dev; struct bma180_data *data; struct iio_dev *indio_dev; - enum chip_ids chip; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); @@ -936,11 +935,7 @@ static int bma180_probe(struct i2c_client *client) data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - if (client->dev.of_node) - chip = (uintptr_t)of_device_get_match_data(dev); - else - chip = id->driver_data; - data->part_info = &bma180_part_info[chip]; + data->part_info = i2c_get_match_data(client); ret = iio_read_mount_matrix(dev, &data->orientation); if (ret) @@ -1092,11 +1087,11 @@ static int bma180_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); static const struct i2c_device_id bma180_ids[] = { - { "bma023", BMA023 }, - { "bma150", BMA150 }, - { "bma180", BMA180 }, - { "bma250", BMA250 }, - { "smb380", BMA150 }, + { "bma023", (kernel_ulong_t)&bma180_part_info[BMA023] }, + { "bma150", (kernel_ulong_t)&bma180_part_info[BMA150] }, + { "bma180", (kernel_ulong_t)&bma180_part_info[BMA180] }, + { "bma250", (kernel_ulong_t)&bma180_part_info[BMA250] }, + { "smb380", (kernel_ulong_t)&bma180_part_info[BMA150] }, { } }; @@ -1105,23 +1100,23 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids); static const struct of_device_id bma180_of_match[] = { { .compatible = "bosch,bma023", - .data = (void *)BMA023 + .data = &bma180_part_info[BMA023] }, { .compatible = "bosch,bma150", - .data = (void *)BMA150 + .data = &bma180_part_info[BMA150] }, { .compatible = "bosch,bma180", - .data = (void *)BMA180 + .data = &bma180_part_info[BMA180] }, { .compatible = "bosch,bma250", - .data = (void *)BMA250 + .data = &bma180_part_info[BMA250] }, { .compatible = "bosch,smb380", - .data = (void *)BMA150 + .data = &bma180_part_info[BMA150] }, { } }; diff --git a/drivers/iio/accel/fxls8962af.h b/drivers/iio/accel/fxls8962af.h index 9cbe98c3ba9a..6eaa2803b26f 100644 --- a/drivers/iio/accel/fxls8962af.h +++ b/drivers/iio/accel/fxls8962af.h @@ -14,7 +14,6 @@ enum { }; int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq); -int fxls8962af_core_remove(struct device *dev); extern const struct dev_pm_ops fxls8962af_pm_ops; extern const struct regmap_config fxls8962af_i2c_regmap_conf; diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 5eac7ea19993..9b7a73a4c48a 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -422,7 +422,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_accel_3d_remove(struct platform_device *pdev) +static void hid_accel_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -431,8 +431,6 @@ static int hid_accel_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes); - - return 0; } static const struct platform_device_id hid_accel_3d_ids[] = { @@ -454,7 +452,7 @@ static struct platform_driver hid_accel_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_accel_3d_probe, - .remove = hid_accel_3d_remove, + .remove_new = hid_accel_3d_remove, }; module_platform_driver(hid_accel_3d_platform_driver); diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index b0ac78e85dad..8a1d4fc28ddd 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2022 ROHM Semiconductors * - * ROHM/KIONIX KX022A accelerometer driver + * ROHM/KIONIX accelerometer driver */ #include <linux/i2c.h> @@ -15,6 +15,7 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; + const struct kx022a_chip_info *chip_info; struct regmap *regmap; if (!i2c->irq) { @@ -22,16 +23,30 @@ static int kx022a_i2c_probe(struct i2c_client *i2c) return -EINVAL; } - regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap); + chip_info = i2c_get_match_data(i2c); + if (!chip_info) + return -EINVAL; + + regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initialize Regmap\n"); - return kx022a_probe_internal(dev); + return kx022a_probe_internal(dev, chip_info); } +static const struct i2c_device_id kx022a_i2c_id[] = { + { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, + { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, + { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id); + static const struct of_device_id kx022a_of_match[] = { - { .compatible = "kionix,kx022a", }, + { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, + { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, + { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); @@ -43,6 +58,7 @@ static struct i2c_driver kx022a_i2c_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = kx022a_i2c_probe, + .id_table = kx022a_i2c_id, }; module_i2c_driver(kx022a_i2c_driver); diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c index f45a46899a5f..f798b964d0b5 100644 --- a/drivers/iio/accel/kionix-kx022a-spi.c +++ b/drivers/iio/accel/kionix-kx022a-spi.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2022 ROHM Semiconductors * - * ROHM/KIONIX KX022A accelerometer driver + * ROHM/KIONIX accelerometer driver */ #include <linux/interrupt.h> @@ -15,6 +15,7 @@ static int kx022a_spi_probe(struct spi_device *spi) { struct device *dev = &spi->dev; + const struct kx022a_chip_info *chip_info; struct regmap *regmap; if (!spi->irq) { @@ -22,22 +23,30 @@ static int kx022a_spi_probe(struct spi_device *spi) return -EINVAL; } - regmap = devm_regmap_init_spi(spi, &kx022a_regmap); + chip_info = spi_get_device_match_data(spi); + if (!chip_info) + return -EINVAL; + + regmap = devm_regmap_init_spi(spi, chip_info->regmap_config); if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initialize Regmap\n"); - return kx022a_probe_internal(dev); + return kx022a_probe_internal(dev, chip_info); } static const struct spi_device_id kx022a_id[] = { - { "kx022a" }, + { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info }, + { .name = "kx132-1211", .driver_data = (kernel_ulong_t)&kx132_chip_info }, + { .name = "kx132acr-lbz", .driver_data = (kernel_ulong_t)&kx132acr_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, kx022a_id); static const struct of_device_id kx022a_of_match[] = { - { .compatible = "kionix,kx022a", }, + { .compatible = "kionix,kx022a", .data = &kx022a_chip_info }, + { .compatible = "kionix,kx132-1211", .data = &kx132_chip_info }, + { .compatible = "rohm,kx132acr-lbz", .data = &kx132acr_chip_info }, { } }; MODULE_DEVICE_TABLE(of, kx022a_of_match); diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 4ea3c6718ed4..60864be3a667 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2022 ROHM Semiconductors * - * ROHM/KIONIX KX022A accelerometer driver + * ROHM/KIONIX accelerometer driver */ #include <linux/delay.h> @@ -15,7 +15,7 @@ #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> -#include <linux/string_helpers.h> +#include <linux/string_choices.h> #include <linux/units.h> #include <linux/iio/iio.h> @@ -48,7 +48,7 @@ enum { KX022A_STATE_FIFO, }; -/* Regmap configs */ +/* kx022a Regmap configs */ static const struct regmap_range kx022a_volatile_ranges[] = { { .range_min = KX022A_REG_XHP_L, @@ -138,7 +138,7 @@ static const struct regmap_access_table kx022a_nir_regs = { .n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges), }; -const struct regmap_config kx022a_regmap = { +static const struct regmap_config kx022a_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_table = &kx022a_volatile_regs, @@ -149,10 +149,121 @@ const struct regmap_config kx022a_regmap = { .max_register = KX022A_MAX_REGISTER, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A); + +/* Regmap configs kx132 */ +static const struct regmap_range kx132_volatile_ranges[] = { + { + .range_min = KX132_REG_XADP_L, + .range_max = KX132_REG_COTR, + }, { + .range_min = KX132_REG_TSCP, + .range_max = KX132_REG_INT_REL, + }, { + /* The reset bit will be cleared by sensor */ + .range_min = KX132_REG_CNTL2, + .range_max = KX132_REG_CNTL2, + }, { + .range_min = KX132_REG_CNTL5, + .range_max = KX132_REG_CNTL5, + }, { + .range_min = KX132_REG_BUF_STATUS_1, + .range_max = KX132_REG_BUF_READ, + }, +}; + +static const struct regmap_access_table kx132_volatile_regs = { + .yes_ranges = &kx132_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(kx132_volatile_ranges), +}; + +static const struct regmap_range kx132_precious_ranges[] = { + { + .range_min = KX132_REG_INT_REL, + .range_max = KX132_REG_INT_REL, + }, +}; + +static const struct regmap_access_table kx132_precious_regs = { + .yes_ranges = &kx132_precious_ranges[0], + .n_yes_ranges = ARRAY_SIZE(kx132_precious_ranges), +}; + +static const struct regmap_range kx132_read_only_ranges[] = { + { + .range_min = KX132_REG_XADP_L, + .range_max = KX132_REG_INT_REL, + }, { + .range_min = KX132_REG_BUF_STATUS_1, + .range_max = KX132_REG_BUF_STATUS_2, + }, { + .range_min = KX132_REG_BUF_READ, + .range_max = KX132_REG_BUF_READ, + }, { + /* Kionix reserved registers: should not be written */ + .range_min = 0x28, + .range_max = 0x28, + }, { + .range_min = 0x35, + .range_max = 0x36, + }, { + .range_min = 0x3c, + .range_max = 0x48, + }, { + .range_min = 0x4e, + .range_max = 0x5c, + }, { + .range_min = 0x77, + .range_max = 0x7f, + }, +}; + +static const struct regmap_access_table kx132_ro_regs = { + .no_ranges = &kx132_read_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(kx132_read_only_ranges), +}; + +static const struct regmap_range kx132_write_only_ranges[] = { + { + .range_min = KX132_REG_SELF_TEST, + .range_max = KX132_REG_SELF_TEST, + }, { + .range_min = KX132_REG_BUF_CLEAR, + .range_max = KX132_REG_BUF_CLEAR, + }, +}; + +static const struct regmap_access_table kx132_wo_regs = { + .no_ranges = &kx132_write_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(kx132_write_only_ranges), +}; + +static const struct regmap_range kx132_noinc_read_ranges[] = { + { + .range_min = KX132_REG_BUF_READ, + .range_max = KX132_REG_BUF_READ, + }, +}; + +static const struct regmap_access_table kx132_nir_regs = { + .yes_ranges = &kx132_noinc_read_ranges[0], + .n_yes_ranges = ARRAY_SIZE(kx132_noinc_read_ranges), +}; + +static const struct regmap_config kx132_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &kx132_volatile_regs, + .rd_table = &kx132_wo_regs, + .wr_table = &kx132_ro_regs, + .rd_noinc_table = &kx132_nir_regs, + .precious_table = &kx132_precious_regs, + .max_register = KX132_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, +}; struct kx022a_data { struct regmap *regmap; + const struct kx022a_chip_info *chip_info; struct iio_trigger *trig; struct device *dev; struct iio_mount_matrix orientation; @@ -175,6 +286,8 @@ struct kx022a_data { struct mutex mutex; u8 watermark; + __le16 *fifo_buffer; + /* 3 x 16bit accel data + timestamp */ __le16 buffer[8] __aligned(IIO_DMA_MINALIGN); struct { @@ -208,7 +321,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = { { } }; -#define KX022A_ACCEL_CHAN(axis, index) \ +#define KX022A_ACCEL_CHAN(axis, reg, index) \ { \ .type = IIO_ACCEL, \ .modified = 1, \ @@ -220,7 +333,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = { BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .ext_info = kx022a_ext_info, \ - .address = KX022A_REG_##axis##OUT_L, \ + .address = reg, \ .scan_index = index, \ .scan_type = { \ .sign = 's', \ @@ -231,9 +344,16 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = { } static const struct iio_chan_spec kx022a_channels[] = { - KX022A_ACCEL_CHAN(X, 0), - KX022A_ACCEL_CHAN(Y, 1), - KX022A_ACCEL_CHAN(Z, 2), + KX022A_ACCEL_CHAN(X, KX022A_REG_XOUT_L, 0), + KX022A_ACCEL_CHAN(Y, KX022A_REG_YOUT_L, 1), + KX022A_ACCEL_CHAN(Z, KX022A_REG_ZOUT_L, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec kx132_channels[] = { + KX022A_ACCEL_CHAN(X, KX132_REG_XOUT_L, 0), + KX022A_ACCEL_CHAN(Y, KX132_REG_YOUT_L, 1), + KX022A_ACCEL_CHAN(Z, KX132_REG_ZOUT_L, 2), IIO_CHAN_SOFT_TIMESTAMP(3), }; @@ -332,16 +452,15 @@ static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on) int ret; if (on) - ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL, + ret = regmap_set_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_PC1); else - ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL, + ret = regmap_clear_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_PC1); if (ret) dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret); return ret; - } static int kx022a_turn_off_lock(struct kx022a_data *data) @@ -403,7 +522,7 @@ static int kx022a_write_raw(struct iio_dev *idev, break; ret = regmap_update_bits(data->regmap, - KX022A_REG_ODCNTL, + data->chip_info->odcntl, KX022A_MASK_ODR, n); data->odr_ns = kx022a_odrs[n]; kx022a_turn_on_unlock(data); @@ -424,7 +543,7 @@ static int kx022a_write_raw(struct iio_dev *idev, if (ret) break; - ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL, + ret = regmap_update_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_GSEL, n << KX022A_GSEL_SHIFT); kx022a_turn_on_unlock(data); @@ -446,7 +565,7 @@ static int kx022a_fifo_set_wmi(struct kx022a_data *data) threshold = data->watermark; - return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1, + return regmap_update_bits(data->regmap, data->chip_info->buf_cntl1, KX022A_MASK_WM_TH, threshold); } @@ -489,7 +608,7 @@ static int kx022a_read_raw(struct iio_dev *idev, return ret; case IIO_CHAN_INFO_SAMP_FREQ: - ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, ®val); + ret = regmap_read(data->regmap, data->chip_info->odcntl, ®val); if (ret) return ret; @@ -504,7 +623,7 @@ static int kx022a_read_raw(struct iio_dev *idev, return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SCALE: - ret = regmap_read(data->regmap, KX022A_REG_CNTL, ®val); + ret = regmap_read(data->regmap, data->chip_info->cntl, ®val); if (ret < 0) return ret; @@ -520,8 +639,7 @@ static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val) { struct kx022a_data *data = iio_priv(idev); - if (val > KX022A_FIFO_LENGTH) - val = KX022A_FIFO_LENGTH; + val = min(data->chip_info->fifo_length, val); mutex_lock(&data->mutex); data->watermark = val; @@ -582,30 +700,56 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data) */ data->timestamp = 0; - return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0); + return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0); +} + +static int kx022a_get_fifo_bytes_available(struct kx022a_data *data) +{ + int ret, fifo_bytes; + + ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes); + if (ret) { + dev_err(data->dev, "Error reading buffer status\n"); + return ret; + } + + if (fifo_bytes == KX022A_FIFO_FULL_VALUE) + return KX022A_FIFO_MAX_BYTES; + + return fifo_bytes; +} + +static int kx132_get_fifo_bytes_available(struct kx022a_data *data) +{ + __le16 buf_status; + int ret, fifo_bytes; + + ret = regmap_bulk_read(data->regmap, data->chip_info->buf_status1, + &buf_status, sizeof(buf_status)); + if (ret) { + dev_err(data->dev, "Error reading buffer status\n"); + return ret; + } + + fifo_bytes = le16_to_cpu(buf_status); + fifo_bytes &= data->chip_info->buf_smp_lvl_mask; + fifo_bytes = min((unsigned int)fifo_bytes, data->chip_info->fifo_length * + KX022A_FIFO_SAMPLES_SIZE_BYTES); + + return fifo_bytes; } static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples, bool irq) { struct kx022a_data *data = iio_priv(idev); - struct device *dev = regmap_get_device(data->regmap); - __le16 buffer[KX022A_FIFO_LENGTH * 3]; uint64_t sample_period; int count, fifo_bytes; bool renable = false; int64_t tstamp; int ret, i; - ret = regmap_read(data->regmap, KX022A_REG_BUF_STATUS_1, &fifo_bytes); - if (ret) { - dev_err(dev, "Error reading buffer status\n"); - return ret; - } - - /* Let's not overflow if we for some reason get bogus value from i2c */ - if (fifo_bytes == KX022A_FIFO_FULL_VALUE) - fifo_bytes = KX022A_FIFO_MAX_BYTES; + fifo_bytes = data->chip_info->get_fifo_bytes_available(data); if (fifo_bytes % KX022A_FIFO_SAMPLES_SIZE_BYTES) dev_warn(data->dev, "Bad FIFO alignment. Data may be corrupt\n"); @@ -669,13 +813,13 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples, } fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES; - ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ, - &buffer[0], fifo_bytes); + ret = regmap_noinc_read(data->regmap, data->chip_info->buf_read, + data->fifo_buffer, fifo_bytes); if (ret) goto renable_out; for (i = 0; i < count; i++) { - __le16 *sam = &buffer[i * 3]; + __le16 *sam = &data->fifo_buffer[i * 3]; __le16 *chs; int bit; @@ -722,10 +866,10 @@ static const struct iio_info kx022a_info = { static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en) { if (en) - return regmap_set_bits(data->regmap, KX022A_REG_CNTL, + return regmap_set_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_DRDY); - return regmap_clear_bits(data->regmap, KX022A_REG_CNTL, + return regmap_clear_bits(data->regmap, data->chip_info->cntl, KX022A_MASK_DRDY); } @@ -760,7 +904,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data) if (ret) goto unlock_out; - ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2, + ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BUF_EN); if (ret) goto unlock_out; @@ -769,6 +913,8 @@ static int kx022a_fifo_disable(struct kx022a_data *data) kx022a_drop_fifo_contents(data); + kfree(data->fifo_buffer); + return kx022a_turn_on_unlock(data); unlock_out: @@ -791,6 +937,12 @@ static int kx022a_fifo_enable(struct kx022a_data *data) { int ret; + data->fifo_buffer = kmalloc_array(data->chip_info->fifo_length, + KX022A_FIFO_SAMPLES_SIZE_BYTES, + GFP_KERNEL); + if (!data->fifo_buffer) + return -ENOMEM; + ret = kx022a_turn_off_lock(data); if (ret) return ret; @@ -801,7 +953,7 @@ static int kx022a_fifo_enable(struct kx022a_data *data) goto unlock_out; /* Enable buffer */ - ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2, + ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BUF_EN); if (ret) goto unlock_out; @@ -847,7 +999,7 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p) struct kx022a_data *data = iio_priv(idev); int ret; - ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer, + ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l, data->buffer, KX022A_FIFO_SAMPLES_SIZE_BYTES); if (ret < 0) goto err_read; @@ -895,7 +1047,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private) if (data->state & KX022A_STATE_FIFO) { int ok; - ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true); + ok = __kx022a_fifo_flush(idev, data->chip_info->fifo_length, true); if (ok > 0) ret = IRQ_HANDLED; } @@ -948,7 +1100,7 @@ static int kx022a_chip_init(struct kx022a_data *data) int ret, val; /* Reset the senor */ - ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST); + ret = regmap_write(data->regmap, data->chip_info->cntl2, KX022A_MASK_SRST); if (ret) return ret; @@ -958,7 +1110,7 @@ static int kx022a_chip_init(struct kx022a_data *data) */ msleep(1); - ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val, + ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val, !(val & KX022A_MASK_SRST), KX022A_SOFT_RESET_WAIT_TIME_US, KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US); @@ -968,14 +1120,14 @@ static int kx022a_chip_init(struct kx022a_data *data) return ret; } - ret = regmap_reinit_cache(data->regmap, &kx022a_regmap); + ret = regmap_reinit_cache(data->regmap, data->chip_info->regmap_config); if (ret) { dev_err(data->dev, "Failed to reinit reg cache\n"); return ret; } /* set data res 16bit */ - ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2, + ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BRES16); if (ret) { dev_err(data->dev, "Failed to set data resolution\n"); @@ -985,7 +1137,90 @@ static int kx022a_chip_init(struct kx022a_data *data) return kx022a_prepare_irq_pin(data); } -int kx022a_probe_internal(struct device *dev) +const struct kx022a_chip_info kx022a_chip_info = { + .name = "kx022-accel", + .regmap_config = &kx022a_regmap_config, + .channels = kx022a_channels, + .num_channels = ARRAY_SIZE(kx022a_channels), + .fifo_length = KX022A_FIFO_LENGTH, + .who = KX022A_REG_WHO, + .id = KX022A_ID, + .cntl = KX022A_REG_CNTL, + .cntl2 = KX022A_REG_CNTL2, + .odcntl = KX022A_REG_ODCNTL, + .buf_cntl1 = KX022A_REG_BUF_CNTL1, + .buf_cntl2 = KX022A_REG_BUF_CNTL2, + .buf_clear = KX022A_REG_BUF_CLEAR, + .buf_status1 = KX022A_REG_BUF_STATUS_1, + .buf_read = KX022A_REG_BUF_READ, + .inc1 = KX022A_REG_INC1, + .inc4 = KX022A_REG_INC4, + .inc5 = KX022A_REG_INC5, + .inc6 = KX022A_REG_INC6, + .xout_l = KX022A_REG_XOUT_L, + .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, +}; +EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A); + +const struct kx022a_chip_info kx132_chip_info = { + .name = "kx132-1211", + .regmap_config = &kx132_regmap_config, + .channels = kx132_channels, + .num_channels = ARRAY_SIZE(kx132_channels), + .fifo_length = KX132_FIFO_LENGTH, + .who = KX132_REG_WHO, + .id = KX132_ID, + .cntl = KX132_REG_CNTL, + .cntl2 = KX132_REG_CNTL2, + .odcntl = KX132_REG_ODCNTL, + .buf_cntl1 = KX132_REG_BUF_CNTL1, + .buf_cntl2 = KX132_REG_BUF_CNTL2, + .buf_clear = KX132_REG_BUF_CLEAR, + .buf_status1 = KX132_REG_BUF_STATUS_1, + .buf_smp_lvl_mask = KX132_MASK_BUF_SMP_LVL, + .buf_read = KX132_REG_BUF_READ, + .inc1 = KX132_REG_INC1, + .inc4 = KX132_REG_INC4, + .inc5 = KX132_REG_INC5, + .inc6 = KX132_REG_INC6, + .xout_l = KX132_REG_XOUT_L, + .get_fifo_bytes_available = kx132_get_fifo_bytes_available, +}; +EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A); + +/* + * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is + * exact subset of KX022A. KX132ACR-LBZ is meant to be used for industrial + * applications and the tap/double tap, free fall and tilt engines were + * removed. Rest of the registers and functionalities (excluding the ID + * register) are exact match to what is found in KX022. + */ +const struct kx022a_chip_info kx132acr_chip_info = { + .name = "kx132acr-lbz", + .regmap_config = &kx022a_regmap_config, + .channels = kx022a_channels, + .num_channels = ARRAY_SIZE(kx022a_channels), + .fifo_length = KX022A_FIFO_LENGTH, + .who = KX022A_REG_WHO, + .id = KX132ACR_LBZ_ID, + .cntl = KX022A_REG_CNTL, + .cntl2 = KX022A_REG_CNTL2, + .odcntl = KX022A_REG_ODCNTL, + .buf_cntl1 = KX022A_REG_BUF_CNTL1, + .buf_cntl2 = KX022A_REG_BUF_CNTL2, + .buf_clear = KX022A_REG_BUF_CLEAR, + .buf_status1 = KX022A_REG_BUF_STATUS_1, + .buf_read = KX022A_REG_BUF_READ, + .inc1 = KX022A_REG_INC1, + .inc4 = KX022A_REG_INC4, + .inc5 = KX022A_REG_INC5, + .inc6 = KX022A_REG_INC6, + .xout_l = KX022A_REG_XOUT_L, + .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, +}; +EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, IIO_KX022A); + +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) { static const char * const regulator_names[] = {"io-vdd", "vdd"}; struct iio_trigger *indio_trig; @@ -1012,6 +1247,7 @@ int kx022a_probe_internal(struct device *dev) return -ENOMEM; data = iio_priv(idev); + data->chip_info = chip_info; /* * VDD is the analog and digital domain voltage supply and @@ -1022,26 +1258,24 @@ int kx022a_probe_internal(struct device *dev) if (ret && ret != -ENODEV) return dev_err_probe(dev, ret, "failed to enable regulator\n"); - ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id); + ret = regmap_read(regmap, chip_info->who, &chip_id); if (ret) return dev_err_probe(dev, ret, "Failed to access sensor\n"); - if (chip_id != KX022A_ID) { - dev_err(dev, "unsupported device 0x%x\n", chip_id); - return -EINVAL; - } + if (chip_id != chip_info->id) + dev_warn(dev, "unknown device 0x%x\n", chip_id); irq = fwnode_irq_get_byname(fwnode, "INT1"); if (irq > 0) { - data->inc_reg = KX022A_REG_INC1; - data->ien_reg = KX022A_REG_INC4; + data->inc_reg = chip_info->inc1; + data->ien_reg = chip_info->inc4; } else { irq = fwnode_irq_get_byname(fwnode, "INT2"); if (irq < 0) return dev_err_probe(dev, irq, "No suitable IRQ\n"); - data->inc_reg = KX022A_REG_INC5; - data->ien_reg = KX022A_REG_INC6; + data->inc_reg = chip_info->inc5; + data->ien_reg = chip_info->inc6; } data->regmap = regmap; @@ -1050,9 +1284,9 @@ int kx022a_probe_internal(struct device *dev) data->odr_ns = KX022A_DEFAULT_PERIOD_NS; mutex_init(&data->mutex); - idev->channels = kx022a_channels; - idev->num_channels = ARRAY_SIZE(kx022a_channels); - idev->name = "kx022-accel"; + idev->channels = chip_info->channels; + idev->num_channels = chip_info->num_channels; + idev->name = chip_info->name; idev->info = &kx022a_info; idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; idev->available_scan_masks = kx022a_scan_masks; @@ -1110,7 +1344,6 @@ int kx022a_probe_internal(struct device *dev) if (ret) return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); - ret = devm_iio_trigger_register(dev, indio_trig); if (ret) return dev_err_probe(data->dev, ret, diff --git a/drivers/iio/accel/kionix-kx022a.h b/drivers/iio/accel/kionix-kx022a.h index 12424649d438..7060438ad88c 100644 --- a/drivers/iio/accel/kionix-kx022a.h +++ b/drivers/iio/accel/kionix-kx022a.h @@ -13,6 +13,7 @@ #define KX022A_REG_WHO 0x0f #define KX022A_ID 0xc8 +#define KX132ACR_LBZ_ID 0xd8 #define KX022A_REG_CNTL2 0x19 #define KX022A_MASK_SRST BIT(7) @@ -74,9 +75,118 @@ #define KX022A_REG_SELF_TEST 0x60 #define KX022A_MAX_REGISTER 0x60 +#define KX132_REG_WHO 0x13 +#define KX132_ID 0x3d + +#define KX132_FIFO_LENGTH 86 + +#define KX132_REG_CNTL 0x1b +#define KX132_REG_CNTL2 0x1c +#define KX132_REG_CNTL5 0x1f +#define KX132_MASK_RES BIT(6) +#define KX132_GSEL_2 0x0 +#define KX132_GSEL_4 BIT(3) +#define KX132_GSEL_8 BIT(4) +#define KX132_GSEL_16 GENMASK(4, 3) + +#define KX132_REG_INS2 0x17 +#define KX132_MASK_INS2_WMI BIT(5) + +#define KX132_REG_XADP_L 0x02 +#define KX132_REG_XOUT_L 0x08 +#define KX132_REG_YOUT_L 0x0a +#define KX132_REG_ZOUT_L 0x0c +#define KX132_REG_COTR 0x12 +#define KX132_REG_TSCP 0x14 +#define KX132_REG_INT_REL 0x1a + +#define KX132_REG_ODCNTL 0x21 + +#define KX132_REG_BTS_WUF_TH 0x4a + +#define KX132_REG_BUF_CNTL1 0x5e +#define KX132_REG_BUF_CNTL2 0x5f +#define KX132_REG_BUF_STATUS_1 0x60 +#define KX132_REG_BUF_STATUS_2 0x61 +#define KX132_MASK_BUF_SMP_LVL GENMASK(9, 0) +#define KX132_REG_BUF_CLEAR 0x62 +#define KX132_REG_BUF_READ 0x63 +#define KX132_ODR_SHIFT 3 +#define KX132_FIFO_MAX_WMI_TH 86 + +#define KX132_REG_INC1 0x22 +#define KX132_REG_INC5 0x26 +#define KX132_REG_INC6 0x27 +#define KX132_IPOL_LOW 0 +#define KX132_IPOL_HIGH KX022A_MASK_IPOL +#define KX132_ITYP_PULSE KX022A_MASK_ITYP + +#define KX132_REG_INC4 0x25 + +#define KX132_REG_SELF_TEST 0x5d +#define KX132_MAX_REGISTER 0x76 + struct device; -int kx022a_probe_internal(struct device *dev); -extern const struct regmap_config kx022a_regmap; +struct kx022a_data; + +/** + * struct kx022a_chip_info - Kionix accelerometer chip specific information + * + * @name: name of the device + * @regmap_config: pointer to register map configuration + * @channels: pointer to iio_chan_spec array + * @num_channels: number of iio_chan_spec channels + * @fifo_length: number of 16-bit samples in a full buffer + * @buf_smp_lvl_mask: buffer sample level mask + * @who: WHO_AM_I register + * @id: WHO_AM_I register value + * @cntl: control register 1 + * @cntl2: control register 2 + * @odcntl: output data control register + * @buf_cntl1: buffer control register 1 + * @buf_cntl2: buffer control register 2 + * @buf_clear: buffer clear register + * @buf_status1: buffer status register 1 + * @buf_read: buffer read register + * @inc1: interrupt control register 1 + * @inc4: interrupt control register 4 + * @inc5: interrupt control register 5 + * @inc6: interrupt control register 6 + * @xout_l: x-axis output least significant byte + * @get_fifo_bytes_available: function pointer to get amount of acceleration + * data bytes currently stored in the sensor's FIFO + * buffer + */ +struct kx022a_chip_info { + const char *name; + const struct regmap_config *regmap_config; + const struct iio_chan_spec *channels; + unsigned int num_channels; + unsigned int fifo_length; + u16 buf_smp_lvl_mask; + u8 who; + u8 id; + u8 cntl; + u8 cntl2; + u8 odcntl; + u8 buf_cntl1; + u8 buf_cntl2; + u8 buf_clear; + u8 buf_status1; + u8 buf_read; + u8 inc1; + u8 inc4; + u8 inc5; + u8 inc6; + u8 xout_l; + int (*get_fifo_bytes_available)(struct kx022a_data *); +}; + +int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info); + +extern const struct kx022a_chip_info kx022a_chip_info; +extern const struct kx022a_chip_info kx132_chip_info; +extern const struct kx022a_chip_info kx132acr_chip_info; #endif diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index f42a88711486..d3fd0318e47b 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1535,19 +1535,18 @@ static int mma8452_reset(struct i2c_client *client) } static const struct of_device_id mma8452_dt_ids[] = { + { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, { .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] }, { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, - { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, { } }; MODULE_DEVICE_TABLE(of, mma8452_dt_ids); static int mma8452_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct mma8452_data *data; struct iio_dev *indio_dev; int ret; @@ -1560,15 +1559,10 @@ static int mma8452_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); - data->chip_info = device_get_match_data(&client->dev); - if (!data->chip_info) { - if (id) { - data->chip_info = &mma_chip_info_table[id->driver_data]; - } else { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } - } + data->chip_info = i2c_get_match_data(client); + if (!data->chip_info) + return dev_err_probe(&client->dev, -ENODEV, + "unknown device model\n"); ret = iio_read_mount_matrix(&client->dev, &data->orientation); if (ret) @@ -1830,12 +1824,12 @@ static const struct dev_pm_ops mma8452_pm_ops = { }; static const struct i2c_device_id mma8452_id[] = { - { "mma8451", mma8451 }, - { "mma8452", mma8452 }, - { "mma8453", mma8453 }, - { "mma8652", mma8652 }, - { "mma8653", mma8653 }, - { "fxls8471", fxls8471 }, + { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, + { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] }, + { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] }, + { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] }, + { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] }, + { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 6ddcc3c2f840..b8ddbfd98f11 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -33,7 +33,7 @@ #include <linux/pm.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/string_helpers.h> +#include <linux/string_choices.h> #include <linux/units.h> #include <linux/iio/buffer.h> diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 75d142bc14b4..82e8d0b39049 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -476,6 +476,13 @@ static const struct acpi_device_id mxc4005_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); +static const struct of_device_id mxc4005_of_match[] = { + { .compatible = "memsic,mxc4005", }, + { .compatible = "memsic,mxc6655", }, + { }, +}; +MODULE_DEVICE_TABLE(of, mxc4005_of_match); + static const struct i2c_device_id mxc4005_id[] = { {"mxc4005", 0}, {"mxc6655", 0}, @@ -487,6 +494,7 @@ static struct i2c_driver mxc4005_driver = { .driver = { .name = MXC4005_DRV_NAME, .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), + .of_match_table = mxc4005_of_match, }, .probe = mxc4005_probe, .id_table = mxc4005_id, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 517b3db114b8..35f9867da12c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -607,6 +607,16 @@ config LPC32XX_ADC activate only one via device tree selection. Provides direct access via sysfs. +config LTC2309 + tristate "Linear Technology LTC2309 ADC driver" + depends on I2C + help + Say yes here to build support for Linear Technology LTC2309, a low + noise, low power, 8-channel, 12-bit SAR ADC + + This driver can also be built as a module. If so, the module will + be called ltc2309. + config LTC2471 tristate "Linear Technology LTC2471 and LTC2473 ADC driver" depends on I2C @@ -779,14 +789,29 @@ config MCP3422 This driver can also be built as a module. If so, the module will be called mcp3422. +config MCP3564 + tristate "Microchip Technology MCP3461/2/4/R, MCP3561/2/4/R driver" + depends on SPI + depends on IIO + help + Say yes here to build support for Microchip Technology's MCP3461, + MCP3462, MCP3464, MCP3461R, MCP3462R, MCP3464R, MCP3561, MCP3562, + MCP3564, MCP3561R, MCP3562R and MCP3564R analog to digital + converters. + + This driver can also be built as a module. If so, the module will be + called mcp3564. + config MCP3911 tristate "Microchip Technology MCP3911 driver" depends on SPI select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for Microchip Technology's MCP3911 - analog to digital converter. + Say yes here to build support for one of the following + Microchip Technology's analog to digital converters: + MCP3910, MCP3911, MCP3912, MCP3913, MCP3914, + MCP3918 and MCP3919. This driver can also be built as a module. If so, the module will be called mcp3911. diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 2facf979327d..bee11d442af4 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o +obj-$(CONFIG_LTC2309) += ltc2309.o obj-$(CONFIG_LTC2471) += ltc2471.o obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o @@ -71,6 +72,7 @@ obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o obj-$(CONFIG_MAX9611) += max9611.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o +obj-$(CONFIG_MCP3564) += mcp3564.o obj-$(CONFIG_MCP3911) += mcp3911.o obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index 3b1bdd0b531d..80645fee79a4 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -1179,7 +1179,7 @@ out_dis_pm: return ret; } -static int ab8500_gpadc_remove(struct platform_device *pdev) +static void ab8500_gpadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct ab8500_gpadc *gpadc = iio_priv(indio_dev); @@ -1188,8 +1188,6 @@ static int ab8500_gpadc_remove(struct platform_device *pdev) pm_runtime_put_noidle(gpadc->dev); pm_runtime_disable(gpadc->dev); regulator_disable(gpadc->vddadc); - - return 0; } static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops, @@ -1198,7 +1196,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops, static struct platform_driver ab8500_gpadc_driver = { .probe = ab8500_gpadc_probe, - .remove = ab8500_gpadc_remove, + .remove_new = ab8500_gpadc_remove, .driver = { .name = "ab8500-gpadc", .pm = pm_ptr(&ab8500_gpadc_pm_ops), diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c index 5a5dd5e87ffc..feb86fe6c422 100644 --- a/drivers/iio/adc/ad4130.c +++ b/drivers/iio/adc/ad4130.c @@ -1817,18 +1817,12 @@ static const struct clk_ops ad4130_int_clk_ops = { .unprepare = ad4130_int_clk_unprepare, }; -static void ad4130_clk_del_provider(void *of_node) -{ - of_clk_del_provider(of_node); -} - static int ad4130_setup_int_clk(struct ad4130_state *st) { struct device *dev = &st->spi->dev; struct device_node *of_node = dev_of_node(dev); struct clk_init_data init; const char *clk_name; - struct clk *clk; int ret; if (st->int_pin_sel == AD4130_INT_PIN_CLK || @@ -1845,15 +1839,12 @@ static int ad4130_setup_int_clk(struct ad4130_state *st) init.ops = &ad4130_int_clk_ops; st->int_clk_hw.init = &init; - clk = devm_clk_register(dev, &st->int_clk_hw); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - ret = of_clk_add_provider(of_node, of_clk_src_simple_get, clk); + ret = devm_clk_hw_register(dev, &st->int_clk_hw); if (ret) return ret; - return devm_add_action_or_reset(dev, ad4130_clk_del_provider, of_node); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &st->int_clk_hw); } static int ad4130_setup(struct iio_dev *indio_dev) diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index b64fd365f83f..adc3cbe92d6e 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -6,6 +6,7 @@ */ #include <linux/interrupt.h> +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/kernel.h> @@ -43,7 +44,7 @@ #define AD7192_COMM_WEN BIT(7) /* Write Enable */ #define AD7192_COMM_WRITE 0 /* Write Operation */ #define AD7192_COMM_READ BIT(6) /* Read Operation */ -#define AD7192_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */ +#define AD7192_COMM_ADDR_MASK GENMASK(5, 3) /* Register Address Mask */ #define AD7192_COMM_CREAD BIT(2) /* Continuous Read of Data Register */ /* Status Register Bit Designations (AD7192_REG_STAT) */ @@ -56,17 +57,18 @@ #define AD7192_STAT_CH1 BIT(0) /* Channel 1 */ /* Mode Register Bit Designations (AD7192_REG_MODE) */ -#define AD7192_MODE_SEL(x) (((x) & 0x7) << 21) /* Operation Mode Select */ -#define AD7192_MODE_SEL_MASK (0x7 << 21) /* Operation Mode Select Mask */ -#define AD7192_MODE_STA(x) (((x) & 0x1) << 20) /* Status Register transmission */ +#define AD7192_MODE_SEL_MASK GENMASK(23, 21) /* Operation Mode Select Mask */ #define AD7192_MODE_STA_MASK BIT(20) /* Status Register transmission Mask */ -#define AD7192_MODE_CLKSRC(x) (((x) & 0x3) << 18) /* Clock Source Select */ +#define AD7192_MODE_CLKSRC_MASK GENMASK(19, 18) /* Clock Source Select Mask */ +#define AD7192_MODE_AVG_MASK GENMASK(17, 16) + /* Fast Settling Filter Average Select Mask (AD7193 only) */ #define AD7192_MODE_SINC3 BIT(15) /* SINC3 Filter Select */ #define AD7192_MODE_ENPAR BIT(13) /* Parity Enable */ #define AD7192_MODE_CLKDIV BIT(12) /* Clock divide by 2 (AD7190/2 only)*/ #define AD7192_MODE_SCYCLE BIT(11) /* Single cycle conversion */ #define AD7192_MODE_REJ60 BIT(10) /* 50/60Hz notch filter */ -#define AD7192_MODE_RATE(x) ((x) & 0x3FF) /* Filter Update Rate Select */ + /* Filter Update Rate Select Mask */ +#define AD7192_MODE_RATE_MASK GENMASK(9, 0) /* Mode Register: AD7192_MODE_SEL options */ #define AD7192_MODE_CONT 0 /* Continuous Conversion Mode */ @@ -92,13 +94,12 @@ #define AD7192_CONF_CHOP BIT(23) /* CHOP enable */ #define AD7192_CONF_ACX BIT(22) /* AC excitation enable(AD7195 only) */ #define AD7192_CONF_REFSEL BIT(20) /* REFIN1/REFIN2 Reference Select */ -#define AD7192_CONF_CHAN(x) ((x) << 8) /* Channel select */ -#define AD7192_CONF_CHAN_MASK (0x7FF << 8) /* Channel select mask */ +#define AD7192_CONF_CHAN_MASK GENMASK(18, 8) /* Channel select mask */ #define AD7192_CONF_BURN BIT(7) /* Burnout current enable */ #define AD7192_CONF_REFDET BIT(6) /* Reference detect enable */ #define AD7192_CONF_BUF BIT(4) /* Buffered Mode Enable */ #define AD7192_CONF_UNIPOLAR BIT(3) /* Unipolar/Bipolar Enable */ -#define AD7192_CONF_GAIN(x) ((x) & 0x7) /* Gain Select */ +#define AD7192_CONF_GAIN_MASK GENMASK(2, 0) /* Gain Select */ #define AD7192_CH_AIN1P_AIN2M BIT(0) /* AIN1(+) - AIN2(-) */ #define AD7192_CH_AIN3P_AIN4M BIT(1) /* AIN3(+) - AIN4(-) */ @@ -130,7 +131,7 @@ #define CHIPID_AD7192 0x0 #define CHIPID_AD7193 0x2 #define CHIPID_AD7195 0x6 -#define AD7192_ID_MASK 0x0F +#define AD7192_ID_MASK GENMASK(3, 0) /* GPOCON Register Bit Designations (AD7192_REG_GPOCON) */ #define AD7192_GPOCON_BPDSW BIT(6) /* Bridge power-down switch enable */ @@ -172,6 +173,9 @@ enum { struct ad7192_chip_info { unsigned int chip_id; const char *name; + const struct iio_chan_spec *channels; + u8 num_channels; + const struct iio_info *info; }; struct ad7192_state { @@ -181,10 +185,10 @@ struct ad7192_state { struct clk *mclk; u16 int_vref_mv; u32 fclk; - u32 f_order; u32 mode; u32 conf; u32 scale_avail[8][2]; + u32 oversampling_ratio_avail[4]; u8 gpocon; u8 clock_sel; struct mutex lock; /* protect sensor state */ @@ -273,7 +277,7 @@ static int ad7192_set_channel(struct ad_sigma_delta *sd, unsigned int channel) struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd); st->conf &= ~AD7192_CONF_CHAN_MASK; - st->conf |= AD7192_CONF_CHAN(channel); + st->conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, channel); return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf); } @@ -284,7 +288,7 @@ static int ad7192_set_mode(struct ad_sigma_delta *sd, struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd); st->mode &= ~AD7192_MODE_SEL_MASK; - st->mode |= AD7192_MODE_SEL(mode); + st->mode |= FIELD_PREP(AD7192_MODE_SEL_MASK, mode); return ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); } @@ -296,7 +300,7 @@ static int ad7192_append_status(struct ad_sigma_delta *sd, bool append) int ret; mode &= ~AD7192_MODE_STA_MASK; - mode |= AD7192_MODE_STA(append); + mode |= FIELD_PREP(AD7192_MODE_STA_MASK, append); ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, mode); if (ret < 0) @@ -400,17 +404,17 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) if (ret) return ret; - id &= AD7192_ID_MASK; + id = FIELD_GET(AD7192_ID_MASK, id); if (id != st->chip_info->chip_id) dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X != 0x%X)\n", id, st->chip_info->chip_id); - st->mode = AD7192_MODE_SEL(AD7192_MODE_IDLE) | - AD7192_MODE_CLKSRC(st->clock_sel) | - AD7192_MODE_RATE(480); + st->mode = FIELD_PREP(AD7192_MODE_SEL_MASK, AD7192_MODE_IDLE) | + FIELD_PREP(AD7192_MODE_CLKSRC_MASK, st->clock_sel) | + FIELD_PREP(AD7192_MODE_RATE_MASK, 480); - st->conf = AD7192_CONF_GAIN(0); + st->conf = FIELD_PREP(AD7192_CONF_GAIN_MASK, 0); rej60_en = of_property_read_bool(np, "adi,rejection-60-Hz-enable"); if (rej60_en) @@ -421,7 +425,6 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) st->conf |= AD7192_CONF_REFSEL; st->conf &= ~AD7192_CONF_CHOP; - st->f_order = AD7192_NO_SYNC_FILTER; buf_en = of_property_read_bool(np, "adi,buffer-enable"); if (buf_en) @@ -456,13 +459,18 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device_node *np) for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { scale_uv = ((u64)st->int_vref_mv * 100000000) >> (indio_dev->channels[0].scan_type.realbits - - ((st->conf & AD7192_CONF_UNIPOLAR) ? 0 : 1)); + !FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf)); scale_uv >>= i; st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10; st->scale_avail[i][0] = scale_uv; } + st->oversampling_ratio_avail[0] = 1; + st->oversampling_ratio_avail[1] = 2; + st->oversampling_ratio_avail[2] = 8; + st->oversampling_ratio_avail[3] = 16; + return 0; } @@ -473,7 +481,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); - return sysfs_emit(buf, "%d\n", !!(st->conf & AD7192_CONF_ACX)); + return sysfs_emit(buf, "%ld\n", FIELD_GET(AD7192_CONF_ACX, st->conf)); } static ssize_t ad7192_show_bridge_switch(struct device *dev, @@ -483,7 +491,8 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); - return sysfs_emit(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW)); + return sysfs_emit(buf, "%ld\n", + FIELD_GET(AD7192_GPOCON_BPDSW, st->gpocon)); } static ssize_t ad7192_set(struct device *dev, @@ -531,22 +540,66 @@ static ssize_t ad7192_set(struct device *dev, return ret ? ret : len; } +static int ad7192_compute_f_order(struct ad7192_state *st, bool sinc3_en, bool chop_en) +{ + u8 avg_factor_selected, oversampling_ratio; + + avg_factor_selected = FIELD_GET(AD7192_MODE_AVG_MASK, st->mode); + + if (!avg_factor_selected && !chop_en) + return 1; + + oversampling_ratio = st->oversampling_ratio_avail[avg_factor_selected]; + + if (sinc3_en) + return AD7192_SYNC3_FILTER + oversampling_ratio - 1; + + return AD7192_SYNC4_FILTER + oversampling_ratio - 1; +} + +static int ad7192_get_f_order(struct ad7192_state *st) +{ + bool sinc3_en, chop_en; + + sinc3_en = FIELD_GET(AD7192_MODE_SINC3, st->mode); + chop_en = FIELD_GET(AD7192_CONF_CHOP, st->conf); + + return ad7192_compute_f_order(st, sinc3_en, chop_en); +} + +static int ad7192_compute_f_adc(struct ad7192_state *st, bool sinc3_en, + bool chop_en) +{ + unsigned int f_order = ad7192_compute_f_order(st, sinc3_en, chop_en); + + return DIV_ROUND_CLOSEST(st->fclk, + f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); +} + +static int ad7192_get_f_adc(struct ad7192_state *st) +{ + unsigned int f_order = ad7192_get_f_order(st); + + return DIV_ROUND_CLOSEST(st->fclk, + f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode)); +} + static void ad7192_get_available_filter_freq(struct ad7192_state *st, int *freq) { unsigned int fadc; /* Formulas for filter at page 25 of the datasheet */ - fadc = DIV_ROUND_CLOSEST(st->fclk, - AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode)); + fadc = ad7192_compute_f_adc(st, false, true); freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024); - fadc = DIV_ROUND_CLOSEST(st->fclk, - AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode)); + fadc = ad7192_compute_f_adc(st, true, true); freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024); - fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode)); + fadc = ad7192_compute_f_adc(st, false, false); freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024); + + fadc = ad7192_compute_f_adc(st, true, false); freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024); } @@ -629,25 +682,21 @@ static int ad7192_set_3db_filter_freq(struct ad7192_state *st, switch (idx) { case 0: - st->f_order = AD7192_SYNC4_FILTER; st->mode &= ~AD7192_MODE_SINC3; st->conf |= AD7192_CONF_CHOP; break; case 1: - st->f_order = AD7192_SYNC3_FILTER; st->mode |= AD7192_MODE_SINC3; st->conf |= AD7192_CONF_CHOP; break; case 2: - st->f_order = AD7192_NO_SYNC_FILTER; st->mode &= ~AD7192_MODE_SINC3; st->conf &= ~AD7192_CONF_CHOP; break; case 3: - st->f_order = AD7192_NO_SYNC_FILTER; st->mode |= AD7192_MODE_SINC3; st->conf &= ~AD7192_CONF_CHOP; @@ -665,12 +714,11 @@ static int ad7192_get_3db_filter_freq(struct ad7192_state *st) { unsigned int fadc; - fadc = DIV_ROUND_CLOSEST(st->fclk, - st->f_order * AD7192_MODE_RATE(st->mode)); + fadc = ad7192_get_f_adc(st); - if (st->conf & AD7192_CONF_CHOP) + if (FIELD_GET(AD7192_CONF_CHOP, st->conf)) return DIV_ROUND_CLOSEST(fadc * 240, 1024); - if (st->mode & AD7192_MODE_SINC3) + if (FIELD_GET(AD7192_MODE_SINC3, st->mode)) return DIV_ROUND_CLOSEST(fadc * 272, 1024); else return DIV_ROUND_CLOSEST(fadc * 230, 1024); @@ -683,7 +731,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, long m) { struct ad7192_state *st = iio_priv(indio_dev); - bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR); + bool unipolar = FIELD_GET(AD7192_CONF_UNIPOLAR, st->conf); + u8 gain = FIELD_GET(AD7192_CONF_GAIN_MASK, st->conf); switch (m) { case IIO_CHAN_INFO_RAW: @@ -692,8 +741,8 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_VOLTAGE: mutex_lock(&st->lock); - *val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0]; - *val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1]; + *val = st->scale_avail[gain][0]; + *val2 = st->scale_avail[gain][1]; mutex_unlock(&st->lock); return IIO_VAL_INT_PLUS_NANO; case IIO_TEMP: @@ -713,13 +762,15 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, *val -= 273 * ad7192_get_temp_scale(unipolar); return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: - *val = st->fclk / - (st->f_order * 1024 * AD7192_MODE_RATE(st->mode)); + *val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024); return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: *val = ad7192_get_3db_filter_freq(st); *val2 = 1000; return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling_ratio_avail[FIELD_GET(AD7192_MODE_AVG_MASK, st->mode)]; + return IIO_VAL_INT; } return -EINVAL; @@ -747,8 +798,8 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, if (val2 == st->scale_avail[i][1]) { ret = 0; tmp = st->conf; - st->conf &= ~AD7192_CONF_GAIN(-1); - st->conf |= AD7192_CONF_GAIN(i); + st->conf &= ~AD7192_CONF_GAIN_MASK; + st->conf |= FIELD_PREP(AD7192_CONF_GAIN_MASK, i); if (tmp == st->conf) break; ad_sd_write_reg(&st->sd, AD7192_REG_CONF, @@ -764,19 +815,36 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, break; } - div = st->fclk / (val * st->f_order * 1024); + div = st->fclk / (val * ad7192_get_f_order(st) * 1024); if (div < 1 || div > 1023) { ret = -EINVAL; break; } - st->mode &= ~AD7192_MODE_RATE(-1); - st->mode |= AD7192_MODE_RATE(div); + st->mode &= ~AD7192_MODE_RATE_MASK; + st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div); ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); break; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000); break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = -EINVAL; + mutex_lock(&st->lock); + for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++) + if (val == st->oversampling_ratio_avail[i]) { + ret = 0; + tmp = st->mode; + st->mode &= ~AD7192_MODE_AVG_MASK; + st->mode |= FIELD_PREP(AD7192_MODE_AVG_MASK, i); + if (tmp == st->mode) + break; + ad_sd_write_reg(&st->sd, AD7192_REG_MODE, + 3, st->mode); + break; + } + mutex_unlock(&st->lock); + break; default: ret = -EINVAL; } @@ -797,6 +865,8 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return IIO_VAL_INT; default: return -EINVAL; } @@ -817,6 +887,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev, *length = ARRAY_SIZE(st->scale_avail) * 2; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = (int *)st->oversampling_ratio_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(st->oversampling_ratio_avail); + + return IIO_AVAIL_LIST; } return -EINVAL; @@ -831,7 +907,7 @@ static int ad7192_update_scan_mode(struct iio_dev *indio_dev, const unsigned lon conf &= ~AD7192_CONF_CHAN_MASK; for_each_set_bit(i, scan_mask, 8) - conf |= AD7192_CONF_CHAN(i); + conf |= FIELD_PREP(AD7192_CONF_CHAN_MASK, i); ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, conf); if (ret < 0) @@ -862,8 +938,8 @@ static const struct iio_info ad7195_info = { .update_scan_mode = ad7192_update_scan_mode, }; -#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _extend_name, \ - _type, _mask_type_av, _ext_info) \ +#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _type, \ + _mask_all, _mask_type_av, _mask_all_av, _ext_info) \ { \ .type = (_type), \ .differential = ((_channel2) == -1 ? 0 : 1), \ @@ -871,13 +947,14 @@ static const struct iio_info ad7195_info = { .channel = (_channel1), \ .channel2 = (_channel2), \ .address = (_address), \ - .extend_name = (_extend_name), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_OFFSET), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ + (_mask_all), \ .info_mask_shared_by_type_available = (_mask_type_av), \ + .info_mask_shared_by_all_available = (_mask_all_av), \ .ext_info = (_ext_info), \ .scan_index = (_si), \ .scan_type = { \ @@ -889,16 +966,26 @@ static const struct iio_info ad7195_info = { } #define AD719x_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \ - __AD719x_CHANNEL(_si, _channel1, _channel2, _address, NULL, \ - IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE), \ - ad7192_calibsys_ext_info) + __AD719x_CHANNEL(_si, _channel1, _channel2, _address, IIO_VOLTAGE, 0, \ + BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info) #define AD719x_CHANNEL(_si, _channel1, _address) \ - __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info) + __AD719x_CHANNEL(_si, _channel1, -1, _address, IIO_VOLTAGE, 0, \ + BIT(IIO_CHAN_INFO_SCALE), 0, ad7192_calibsys_ext_info) #define AD719x_TEMP_CHANNEL(_si, _address) \ - __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL) + __AD719x_CHANNEL(_si, 0, -1, _address, IIO_TEMP, 0, 0, 0, NULL) + +#define AD7193_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \ + __AD719x_CHANNEL(_si, _channel1, _channel2, _address, \ + IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + ad7192_calibsys_ext_info) + +#define AD7193_CHANNEL(_si, _channel1, _address) \ + AD7193_DIFF_CHANNEL(_si, _channel1, -1, _address) static const struct iio_chan_spec ad7192_channels[] = { AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M), @@ -913,20 +1000,20 @@ static const struct iio_chan_spec ad7192_channels[] = { }; static const struct iio_chan_spec ad7193_channels[] = { - AD719x_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M), - AD719x_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M), - AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M), - AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M), + AD7193_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M), + AD7193_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M), + AD7193_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M), + AD7193_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M), AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP), - AD719x_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M), - AD719x_CHANNEL(6, 1, AD7193_CH_AIN1), - AD719x_CHANNEL(7, 2, AD7193_CH_AIN2), - AD719x_CHANNEL(8, 3, AD7193_CH_AIN3), - AD719x_CHANNEL(9, 4, AD7193_CH_AIN4), - AD719x_CHANNEL(10, 5, AD7193_CH_AIN5), - AD719x_CHANNEL(11, 6, AD7193_CH_AIN6), - AD719x_CHANNEL(12, 7, AD7193_CH_AIN7), - AD719x_CHANNEL(13, 8, AD7193_CH_AIN8), + AD7193_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M), + AD7193_CHANNEL(6, 1, AD7193_CH_AIN1), + AD7193_CHANNEL(7, 2, AD7193_CH_AIN2), + AD7193_CHANNEL(8, 3, AD7193_CH_AIN3), + AD7193_CHANNEL(9, 4, AD7193_CH_AIN4), + AD7193_CHANNEL(10, 5, AD7193_CH_AIN5), + AD7193_CHANNEL(11, 6, AD7193_CH_AIN6), + AD7193_CHANNEL(12, 7, AD7193_CH_AIN7), + AD7193_CHANNEL(13, 8, AD7193_CH_AIN8), IIO_CHAN_SOFT_TIMESTAMP(14), }; @@ -934,39 +1021,33 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = { [ID_AD7190] = { .chip_id = CHIPID_AD7190, .name = "ad7190", + .channels = ad7192_channels, + .num_channels = ARRAY_SIZE(ad7192_channels), + .info = &ad7192_info, }, [ID_AD7192] = { .chip_id = CHIPID_AD7192, .name = "ad7192", + .channels = ad7192_channels, + .num_channels = ARRAY_SIZE(ad7192_channels), + .info = &ad7192_info, }, [ID_AD7193] = { .chip_id = CHIPID_AD7193, .name = "ad7193", + .channels = ad7193_channels, + .num_channels = ARRAY_SIZE(ad7193_channels), + .info = &ad7192_info, }, [ID_AD7195] = { .chip_id = CHIPID_AD7195, .name = "ad7195", + .channels = ad7192_channels, + .num_channels = ARRAY_SIZE(ad7192_channels), + .info = &ad7195_info, }, }; -static int ad7192_channels_config(struct iio_dev *indio_dev) -{ - struct ad7192_state *st = iio_priv(indio_dev); - - switch (st->chip_info->chip_id) { - case CHIPID_AD7193: - indio_dev->channels = ad7193_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7193_channels); - break; - default: - indio_dev->channels = ad7192_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7192_channels); - break; - } - - return 0; -} - static void ad7192_reg_disable(void *reg) { regulator_disable(reg); @@ -1041,15 +1122,9 @@ static int ad7192_probe(struct spi_device *spi) st->chip_info = (void *)spi_get_device_id(spi)->driver_data; indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; - - ret = ad7192_channels_config(indio_dev); - if (ret < 0) - return ret; - - if (st->chip_info->chip_id == CHIPID_AD7195) - indio_dev->info = &ad7195_info; - else - indio_dev->info = &ad7192_info; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + indio_dev->info = st->chip_info->info; ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info); if (ret) diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index df67b63ccf69..d7fd21e7c6e2 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -2486,7 +2486,7 @@ reg_disable: return ret; } -static int at91_adc_remove(struct platform_device *pdev) +static void at91_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct at91_adc_state *st = iio_priv(indio_dev); @@ -2501,8 +2501,6 @@ static int at91_adc_remove(struct platform_device *pdev) regulator_disable(st->vref); regulator_disable(st->reg); - - return 0; } static int at91_adc_suspend(struct device *dev) @@ -2627,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_match); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, - .remove = at91_adc_remove, + .remove_new = at91_adc_remove, .driver = { .name = "at91-sama5d2_adc", .of_match_table = at91_adc_dt_match, diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index de6650f9c4b1..eb501e3c86a5 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1013,28 +1013,25 @@ static int at91_adc_probe(struct platform_device *pdev) st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers"); - if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) { - dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n"); - return -EINVAL; - } + if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) + return dev_err_probe(&idev->dev, -EINVAL, + "Missing adc-channels-used property in the DT.\n"); st->channels_mask = prop; st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode"); - if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { - dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); - return -EINVAL; - } + if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) + return dev_err_probe(&idev->dev, -EINVAL, + "Missing adc-startup-time property in the DT.\n"); st->startup_time = prop; prop = 0; of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop); st->sample_hold_time = prop; - if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { - dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); - return -EINVAL; - } + if (of_property_read_u32(node, "atmel,adc-vref", &prop)) + return dev_err_probe(&idev->dev, -EINVAL, + "Missing adc-vref property in the DT.\n"); st->vref_mv = prop; st->res = st->caps->high_res_bits; @@ -1069,7 +1066,6 @@ static int at91_adc_probe(struct platform_device *pdev) if (IS_ERR(st->reg_base)) return PTR_ERR(st->reg_base); - /* * Disable all IRQs before setting up the handler */ @@ -1077,43 +1073,26 @@ static int at91_adc_probe(struct platform_device *pdev) at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); if (st->caps->has_tsmr) - ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0, - pdev->dev.driver->name, idev); + ret = devm_request_irq(&pdev->dev, st->irq, + at91_adc_9x5_interrupt, 0, + pdev->dev.driver->name, idev); else - ret = request_irq(st->irq, at91_adc_rl_interrupt, 0, - pdev->dev.driver->name, idev); - if (ret) { - dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); - return ret; - } - - st->clk = devm_clk_get(&pdev->dev, "adc_clk"); - if (IS_ERR(st->clk)) { - dev_err(&pdev->dev, "Failed to get the clock.\n"); - ret = PTR_ERR(st->clk); - goto error_free_irq; - } - - ret = clk_prepare_enable(st->clk); - if (ret) { - dev_err(&pdev->dev, - "Could not prepare or enable the clock.\n"); - goto error_free_irq; - } + ret = devm_request_irq(&pdev->dev, st->irq, + at91_adc_rl_interrupt, 0, + pdev->dev.driver->name, idev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to allocate IRQ.\n"); - st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk"); - if (IS_ERR(st->adc_clk)) { - dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); - ret = PTR_ERR(st->adc_clk); - goto error_disable_clk; - } + st->clk = devm_clk_get_enabled(&pdev->dev, "adc_clk"); + if (IS_ERR(st->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(st->clk), + "Could not prepare or enable the clock.\n"); - ret = clk_prepare_enable(st->adc_clk); - if (ret) { - dev_err(&pdev->dev, - "Could not prepare or enable the ADC clock.\n"); - goto error_disable_clk; - } + st->adc_clk = devm_clk_get_enabled(&pdev->dev, "adc_op_clk"); + if (IS_ERR(st->adc_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(st->adc_clk), + "Could not prepare or enable the ADC clock.\n"); /* * Prescaler rate computation using the formula from the Atmel's @@ -1129,11 +1108,9 @@ static int at91_adc_probe(struct platform_device *pdev) prsc = (mstrclk / (2 * adc_clk)) - 1; - if (!st->startup_time) { - dev_err(&pdev->dev, "No startup time available.\n"); - ret = -EINVAL; - goto error_disable_adc_clk; - } + if (!st->startup_time) + return dev_err_probe(&pdev->dev, -EINVAL, + "No startup time available.\n"); ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz); /* @@ -1158,10 +1135,9 @@ static int at91_adc_probe(struct platform_device *pdev) /* Setup the ADC channels available on the board */ ret = at91_adc_channel_init(idev); - if (ret < 0) { - dev_err(&pdev->dev, "Couldn't initialize the channels.\n"); - goto error_disable_adc_clk; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Couldn't initialize the channels.\n"); init_waitqueue_head(&st->wq_data_avail); mutex_init(&st->lock); @@ -1173,21 +1149,20 @@ static int at91_adc_probe(struct platform_device *pdev) */ if (!st->touchscreen_type) { ret = at91_adc_buffer_init(idev); - if (ret < 0) { - dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); - goto error_disable_adc_clk; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Couldn't initialize the buffer.\n"); ret = at91_adc_trigger_init(idev); if (ret < 0) { dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); at91_adc_buffer_remove(idev); - goto error_disable_adc_clk; + return ret; } } else { ret = at91_ts_register(idev, pdev); if (ret) - goto error_disable_adc_clk; + return ret; at91_ts_hw_init(idev, adc_clk_khz); } @@ -1207,16 +1182,10 @@ error_iio_device_register: } else { at91_ts_unregister(st); } -error_disable_adc_clk: - clk_disable_unprepare(st->adc_clk); -error_disable_clk: - clk_disable_unprepare(st->clk); -error_free_irq: - free_irq(st->irq, idev); return ret; } -static int at91_adc_remove(struct platform_device *pdev) +static void at91_adc_remove(struct platform_device *pdev) { struct iio_dev *idev = platform_get_drvdata(pdev); struct at91_adc_state *st = iio_priv(idev); @@ -1228,11 +1197,6 @@ static int at91_adc_remove(struct platform_device *pdev) } else { at91_ts_unregister(st); } - clk_disable_unprepare(st->adc_clk); - clk_disable_unprepare(st->clk); - free_irq(st->irq, idev); - - return 0; } static int at91_adc_suspend(struct device *dev) @@ -1382,7 +1346,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_ids); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, - .remove = at91_adc_remove, + .remove_new = at91_adc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = at91_adc_dt_ids, diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 75bda94dbce1..d6c51b0f48e3 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -745,7 +745,7 @@ fail_map: return ret; } -static int axp20x_remove(struct platform_device *pdev) +static void axp20x_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct axp20x_adc_iio *info = iio_priv(indio_dev); @@ -757,8 +757,6 @@ static int axp20x_remove(struct platform_device *pdev) if (info->data->adc_en2_mask) regmap_write(info->regmap, AXP20X_ADC_EN2, 0); - - return 0; } static struct platform_driver axp20x_adc_driver = { @@ -768,7 +766,7 @@ static struct platform_driver axp20x_adc_driver = { }, .id_table = axp20x_adc_id_match, .probe = axp20x_probe, - .remove = axp20x_remove, + .remove_new = axp20x_remove, }; module_platform_driver(axp20x_adc_driver); diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 0d6885413a7e..5bc514bd5ebc 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -594,7 +594,7 @@ err_adc_enable: return ret; } -static int iproc_adc_remove(struct platform_device *pdev) +static void iproc_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); @@ -602,8 +602,6 @@ static int iproc_adc_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); iproc_adc_disable(indio_dev); clk_disable_unprepare(adc_priv->adc_clk); - - return 0; } static const struct of_device_id iproc_adc_of_match[] = { @@ -614,7 +612,7 @@ MODULE_DEVICE_TABLE(of, iproc_adc_of_match); static struct platform_driver iproc_adc_driver = { .probe = iproc_adc_probe, - .remove = iproc_adc_remove, + .remove_new = iproc_adc_remove, .driver = { .name = "iproc-static-adc", .of_match_table = iproc_adc_of_match, diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index 97d162a3cba4..06cfbbabaf8d 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -691,19 +691,18 @@ unregister_event: return ret; } -static int dln2_adc_remove(struct platform_device *pdev) +static void dln2_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); iio_device_unregister(indio_dev); dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV); - return 0; } static struct platform_driver dln2_adc_driver = { .driver.name = DLN2_ADC_MOD_NAME, .probe = dln2_adc_probe, - .remove = dln2_adc_remove, + .remove_new = dln2_adc_remove, }; module_platform_driver(dln2_adc_driver); diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index a35e6cead67d..971942ce4c66 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -217,15 +217,13 @@ static int ep93xx_adc_probe(struct platform_device *pdev) return ret; } -static int ep93xx_adc_remove(struct platform_device *pdev) +static void ep93xx_adc_remove(struct platform_device *pdev) { struct iio_dev *iiodev = platform_get_drvdata(pdev); struct ep93xx_adc_priv *priv = iio_priv(iiodev); iio_device_unregister(iiodev); clk_disable_unprepare(priv->clk); - - return 0; } static const struct of_device_id ep93xx_adc_of_ids[] = { @@ -240,7 +238,7 @@ static struct platform_driver ep93xx_adc_driver = { .of_match_table = ep93xx_adc_of_ids, }, .probe = ep93xx_adc_probe, - .remove = ep93xx_adc_remove, + .remove_new = ep93xx_adc_remove, }; module_platform_driver(ep93xx_adc_driver); diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index cff1ba57fb16..eb7a2dd59517 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -946,7 +946,7 @@ err_disable_reg: return ret; } -static int exynos_adc_remove(struct platform_device *pdev) +static void exynos_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct exynos_adc *info = iio_priv(indio_dev); @@ -964,8 +964,6 @@ static int exynos_adc_remove(struct platform_device *pdev) exynos_adc_disable_clk(info); exynos_adc_unprepare_clk(info); regulator_disable(info->vdd); - - return 0; } static int exynos_adc_suspend(struct device *dev) @@ -1006,7 +1004,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend, static struct platform_driver exynos_adc_driver = { .probe = exynos_adc_probe, - .remove = exynos_adc_remove, + .remove_new = exynos_adc_remove, .driver = { .name = "exynos-adc", .of_match_table = exynos_adc_match, diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 551e83ae573c..68c813de0605 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -384,7 +384,7 @@ err_regulator_disable: return ret; } -static int mx25_gcq_remove(struct platform_device *pdev) +static void mx25_gcq_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct mx25_gcq_priv *priv = iio_priv(indio_dev); @@ -397,8 +397,6 @@ static int mx25_gcq_remove(struct platform_device *pdev) if (priv->vref[i]) regulator_disable(priv->vref[i]); } - - return 0; } static const struct of_device_id mx25_gcq_ids[] = { @@ -413,7 +411,7 @@ static struct platform_driver mx25_gcq_driver = { .of_match_table = mx25_gcq_ids, }, .probe = mx25_gcq_probe, - .remove = mx25_gcq_remove, + .remove_new = mx25_gcq_remove, }; module_platform_driver(mx25_gcq_driver); diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index f7ee856a6b8b..c80c55fb8c6c 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -580,7 +580,7 @@ error_regulator: return ret; } -static int hx711_remove(struct platform_device *pdev) +static void hx711_remove(struct platform_device *pdev) { struct hx711_data *hx711_data; struct iio_dev *indio_dev; @@ -593,8 +593,6 @@ static int hx711_remove(struct platform_device *pdev) iio_triggered_buffer_cleanup(indio_dev); regulator_disable(hx711_data->reg_avdd); - - return 0; } static const struct of_device_id of_hx711_match[] = { @@ -606,7 +604,7 @@ MODULE_DEVICE_TABLE(of, of_hx711_match); static struct platform_driver hx711_driver = { .probe = hx711_probe, - .remove = hx711_remove, + .remove_new = hx711_remove, .driver = { .name = "hx711-gpio", .of_match_table = of_hx711_match, diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index fff6e5a2d956..fe82198170d5 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -404,7 +404,7 @@ error_regulator_disable: return ret; } -static int imx8qxp_adc_remove(struct platform_device *pdev) +static void imx8qxp_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct imx8qxp_adc *adc = iio_priv(indio_dev); @@ -422,8 +422,6 @@ static int imx8qxp_adc_remove(struct platform_device *pdev) pm_runtime_disable(dev); pm_runtime_put_noidle(dev); - - return 0; } static int imx8qxp_adc_runtime_suspend(struct device *dev) @@ -489,7 +487,7 @@ MODULE_DEVICE_TABLE(of, imx8qxp_adc_match); static struct platform_driver imx8qxp_adc_driver = { .probe = imx8qxp_adc_probe, - .remove = imx8qxp_adc_remove, + .remove_new = imx8qxp_adc_remove, .driver = { .name = ADC_DRIVER_NAME, .of_match_table = imx8qxp_adc_match, diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index dce9ec91e4a7..9bb1e4ba1aee 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -392,7 +392,7 @@ error_regulator_disable: return ret; } -static int imx93_adc_remove(struct platform_device *pdev) +static void imx93_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct imx93_adc *adc = iio_priv(indio_dev); @@ -410,8 +410,6 @@ static int imx93_adc_remove(struct platform_device *pdev) free_irq(adc->irq, adc); clk_disable_unprepare(adc->ipg_clk); regulator_disable(adc->vref); - - return 0; } static int imx93_adc_runtime_suspend(struct device *dev) @@ -468,7 +466,7 @@ MODULE_DEVICE_TABLE(of, imx93_adc_match); static struct platform_driver imx93_adc_driver = { .probe = imx93_adc_probe, - .remove = imx93_adc_remove, + .remove_new = imx93_adc_remove, .driver = { .name = IMX93_ADC_DRIVER_NAME, .of_match_table = imx93_adc_match, diff --git a/drivers/iio/adc/ltc2309.c b/drivers/iio/adc/ltc2309.c new file mode 100644 index 000000000000..8b3a89c1b840 --- /dev/null +++ b/drivers/iio/adc/ltc2309.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The LTC2309 is an 8-Channel, 12-Bit SAR ADC with an I2C Interface. + * + * Datasheet: + * https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf + * + * Copyright (c) 2023, Liam Beguin <liambeguin@gmail.com> + */ +#include <linux/bitfield.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regulator/consumer.h> + +#define LTC2309_ADC_RESOLUTION 12 + +#define LTC2309_DIN_CH_MASK GENMASK(7, 4) +#define LTC2309_DIN_SDN BIT(7) +#define LTC2309_DIN_OSN BIT(6) +#define LTC2309_DIN_S1 BIT(5) +#define LTC2309_DIN_S0 BIT(4) +#define LTC2309_DIN_UNI BIT(3) +#define LTC2309_DIN_SLEEP BIT(2) + +/** + * struct ltc2309 - internal device data structure + * @dev: Device reference + * @client: I2C reference + * @vref: External reference source + * @lock: Lock to serialize data access + * @vref_mv: Internal voltage reference + */ +struct ltc2309 { + struct device *dev; + struct i2c_client *client; + struct regulator *vref; + struct mutex lock; /* serialize data access */ + int vref_mv; +}; + +/* Order matches expected channel address, See datasheet Table 1. */ +enum ltc2309_channels { + LTC2309_CH0_CH1 = 0, + LTC2309_CH2_CH3, + LTC2309_CH4_CH5, + LTC2309_CH6_CH7, + LTC2309_CH1_CH0, + LTC2309_CH3_CH2, + LTC2309_CH5_CH4, + LTC2309_CH7_CH6, + LTC2309_CH0, + LTC2309_CH2, + LTC2309_CH4, + LTC2309_CH6, + LTC2309_CH1, + LTC2309_CH3, + LTC2309_CH5, + LTC2309_CH7, +}; + +#define LTC2309_CHAN(_chan, _addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .address = _addr, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +#define LTC2309_DIFF_CHAN(_chan, _chan2, _addr) { \ + .type = IIO_VOLTAGE, \ + .differential = 1, \ + .indexed = 1, \ + .address = _addr, \ + .channel = _chan, \ + .channel2 = _chan2, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec ltc2309_channels[] = { + LTC2309_CHAN(0, LTC2309_CH0), + LTC2309_CHAN(1, LTC2309_CH1), + LTC2309_CHAN(2, LTC2309_CH2), + LTC2309_CHAN(3, LTC2309_CH3), + LTC2309_CHAN(4, LTC2309_CH4), + LTC2309_CHAN(5, LTC2309_CH5), + LTC2309_CHAN(6, LTC2309_CH6), + LTC2309_CHAN(7, LTC2309_CH7), + LTC2309_DIFF_CHAN(0, 1, LTC2309_CH0_CH1), + LTC2309_DIFF_CHAN(2, 3, LTC2309_CH2_CH3), + LTC2309_DIFF_CHAN(4, 5, LTC2309_CH4_CH5), + LTC2309_DIFF_CHAN(6, 7, LTC2309_CH6_CH7), + LTC2309_DIFF_CHAN(1, 0, LTC2309_CH1_CH0), + LTC2309_DIFF_CHAN(3, 2, LTC2309_CH3_CH2), + LTC2309_DIFF_CHAN(5, 4, LTC2309_CH5_CH4), + LTC2309_DIFF_CHAN(7, 6, LTC2309_CH7_CH6), +}; + +static int ltc2309_read_raw_channel(struct ltc2309 *ltc2309, + unsigned long address, int *val) +{ + int ret; + u16 buf; + u8 din; + + din = FIELD_PREP(LTC2309_DIN_CH_MASK, address & 0x0f) | + FIELD_PREP(LTC2309_DIN_UNI, 1) | + FIELD_PREP(LTC2309_DIN_SLEEP, 0); + + ret = i2c_smbus_write_byte(ltc2309->client, din); + if (ret < 0) { + dev_err(ltc2309->dev, "i2c command failed: %pe\n", + ERR_PTR(ret)); + return ret; + } + + ret = i2c_master_recv(ltc2309->client, (char *)&buf, 2); + if (ret < 0) { + dev_err(ltc2309->dev, "i2c read failed: %pe\n", ERR_PTR(ret)); + return ret; + } + + *val = be16_to_cpu(buf) >> 4; + + return ret; +} + +static int ltc2309_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ltc2309 *ltc2309 = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(<c2309->lock); + ret = ltc2309_read_raw_channel(ltc2309, chan->address, val); + mutex_unlock(<c2309->lock); + if (ret < 0) + return -EINVAL; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = ltc2309->vref_mv; + *val2 = LTC2309_ADC_RESOLUTION; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info ltc2309_info = { + .read_raw = ltc2309_read_raw, +}; + +static void ltc2309_regulator_disable(void *regulator) +{ + regulator_disable(regulator); +} + +static int ltc2309_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct ltc2309 *ltc2309; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*ltc2309)); + if (!indio_dev) + return -ENOMEM; + + ltc2309 = iio_priv(indio_dev); + ltc2309->dev = &indio_dev->dev; + ltc2309->client = client; + ltc2309->vref_mv = 4096; /* Default to the internal ref */ + + indio_dev->name = "ltc2309"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ltc2309_channels; + indio_dev->num_channels = ARRAY_SIZE(ltc2309_channels); + indio_dev->info = <c2309_info; + + ltc2309->vref = devm_regulator_get_optional(&client->dev, "vref"); + if (IS_ERR(ltc2309->vref)) { + ret = PTR_ERR(ltc2309->vref); + if (ret == -ENODEV) + ltc2309->vref = NULL; + else + return ret; + } + + if (ltc2309->vref) { + ret = regulator_enable(ltc2309->vref); + if (ret) + return dev_err_probe(ltc2309->dev, ret, + "failed to enable vref\n"); + + ret = devm_add_action_or_reset(ltc2309->dev, + ltc2309_regulator_disable, + ltc2309->vref); + if (ret) { + return dev_err_probe(ltc2309->dev, ret, + "failed to add regulator_disable action: %d\n", + ret); + } + + ret = regulator_get_voltage(ltc2309->vref); + if (ret < 0) + return ret; + + ltc2309->vref_mv = ret / 1000; + } + + mutex_init(<c2309->lock); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct of_device_id ltc2309_of_match[] = { + { .compatible = "lltc,ltc2309" }, + { } +}; +MODULE_DEVICE_TABLE(of, ltc2309_of_match); + +static const struct i2c_device_id ltc2309_id[] = { + { "ltc2309" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltc2309_id); + +static struct i2c_driver ltc2309_driver = { + .driver = { + .name = "ltc2309", + .of_match_table = ltc2309_of_match, + }, + .probe = ltc2309_probe, + .id_table = ltc2309_id, +}; +module_i2c_driver(ltc2309_driver); + +MODULE_AUTHOR("Liam Beguin <liambeguin@gmail.com>"); +MODULE_DESCRIPTION("Linear Technology LTC2309 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index 5bdd40729611..6401a7727c31 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -95,7 +95,6 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata, static int ltc2497_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct ltc2497_chip_info *chip_info; struct iio_dev *indio_dev; struct ltc2497_driverdata *st; @@ -115,9 +114,7 @@ static int ltc2497_probe(struct i2c_client *client) st->client = client; st->common_ddata.result_and_measure = ltc2497_result_and_measure; - chip_info = device_get_match_data(dev); - if (!chip_info) - chip_info = (const struct ltc2497_chip_info *)id->driver_data; + chip_info = i2c_get_match_data(client); st->common_ddata.chip_info = chip_info; resolution = chip_info->resolution; diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index b31581616ce3..7c2a98b8c3a9 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1599,9 +1599,7 @@ static int max1363_probe(struct i2c_client *client) if (ret) return ret; - st->chip_info = device_get_match_data(&client->dev); - if (!st->chip_info) - st->chip_info = &max1363_chip_info_tbl[id->driver_data]; + st->chip_info = i2c_get_match_data(client); st->client = client; st->vref_uv = st->chip_info->int_vref_mv * 1000; @@ -1669,46 +1667,51 @@ static int max1363_probe(struct i2c_client *client) return devm_iio_device_register(&client->dev, indio_dev); } +#define MAX1363_ID_TABLE(_name, cfg) { \ + .name = _name, \ + .driver_data = (kernel_ulong_t)&max1363_chip_info_tbl[cfg], \ +} + static const struct i2c_device_id max1363_id[] = { - { "max1361", max1361 }, - { "max1362", max1362 }, - { "max1363", max1363 }, - { "max1364", max1364 }, - { "max1036", max1036 }, - { "max1037", max1037 }, - { "max1038", max1038 }, - { "max1039", max1039 }, - { "max1136", max1136 }, - { "max1137", max1137 }, - { "max1138", max1138 }, - { "max1139", max1139 }, - { "max1236", max1236 }, - { "max1237", max1237 }, - { "max1238", max1238 }, - { "max1239", max1239 }, - { "max11600", max11600 }, - { "max11601", max11601 }, - { "max11602", max11602 }, - { "max11603", max11603 }, - { "max11604", max11604 }, - { "max11605", max11605 }, - { "max11606", max11606 }, - { "max11607", max11607 }, - { "max11608", max11608 }, - { "max11609", max11609 }, - { "max11610", max11610 }, - { "max11611", max11611 }, - { "max11612", max11612 }, - { "max11613", max11613 }, - { "max11614", max11614 }, - { "max11615", max11615 }, - { "max11616", max11616 }, - { "max11617", max11617 }, - { "max11644", max11644 }, - { "max11645", max11645 }, - { "max11646", max11646 }, - { "max11647", max11647 }, - {} + MAX1363_ID_TABLE("max1361", max1361), + MAX1363_ID_TABLE("max1362", max1362), + MAX1363_ID_TABLE("max1363", max1363), + MAX1363_ID_TABLE("max1364", max1364), + MAX1363_ID_TABLE("max1036", max1036), + MAX1363_ID_TABLE("max1037", max1037), + MAX1363_ID_TABLE("max1038", max1038), + MAX1363_ID_TABLE("max1039", max1039), + MAX1363_ID_TABLE("max1136", max1136), + MAX1363_ID_TABLE("max1137", max1137), + MAX1363_ID_TABLE("max1138", max1138), + MAX1363_ID_TABLE("max1139", max1139), + MAX1363_ID_TABLE("max1236", max1236), + MAX1363_ID_TABLE("max1237", max1237), + MAX1363_ID_TABLE("max1238", max1238), + MAX1363_ID_TABLE("max1239", max1239), + MAX1363_ID_TABLE("max11600", max11600), + MAX1363_ID_TABLE("max11601", max11601), + MAX1363_ID_TABLE("max11602", max11602), + MAX1363_ID_TABLE("max11603", max11603), + MAX1363_ID_TABLE("max11604", max11604), + MAX1363_ID_TABLE("max11605", max11605), + MAX1363_ID_TABLE("max11606", max11606), + MAX1363_ID_TABLE("max11607", max11607), + MAX1363_ID_TABLE("max11608", max11608), + MAX1363_ID_TABLE("max11609", max11609), + MAX1363_ID_TABLE("max11610", max11610), + MAX1363_ID_TABLE("max11611", max11611), + MAX1363_ID_TABLE("max11612", max11612), + MAX1363_ID_TABLE("max11613", max11613), + MAX1363_ID_TABLE("max11614", max11614), + MAX1363_ID_TABLE("max11615", max11615), + MAX1363_ID_TABLE("max11616", max11616), + MAX1363_ID_TABLE("max11617", max11617), + MAX1363_ID_TABLE("max11644", max11644), + MAX1363_ID_TABLE("max11645", max11645), + MAX1363_ID_TABLE("max11646", max11646), + MAX1363_ID_TABLE("max11647", max11647), + { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, max1363_id); diff --git a/drivers/iio/adc/mcp3564.c b/drivers/iio/adc/mcp3564.c new file mode 100644 index 000000000000..e3f1de5fcc5a --- /dev/null +++ b/drivers/iio/adc/mcp3564.c @@ -0,0 +1,1513 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * IIO driver for MCP356X/MCP356XR and MCP346X/MCP346XR series ADC chip family + * + * Copyright (C) 2022-2023 Microchip Technology Inc. and its subsidiaries + * + * Author: Marius Cristea <marius.cristea@microchip.com> + * + * Datasheet for MCP3561, MCP3562, MCP3564 can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3561-2-4-Family-Data-Sheet-DS20006181C.pdf + * Datasheet for MCP3561R, MCP3562R, MCP3564R can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3561_2_4R-Data-Sheet-DS200006391C.pdf + * Datasheet for MCP3461, MCP3462, MCP3464 can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4-Two-Four-Eight-Channel-153.6-ksps-Low-Noise-16-Bit-Delta-Sigma-ADC-Data-Sheet-20006180D.pdf + * Datasheet for MCP3461R, MCP3462R, MCP3464R can be found here: + * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4R-Family-Data-Sheet-DS20006404C.pdf + */ + +#include <linux/bitfield.h> +#include <linux/iopoll.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/units.h> +#include <linux/util_macros.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define MCP3564_ADCDATA_REG 0x00 + +#define MCP3564_CONFIG0_REG 0x01 +#define MCP3564_CONFIG0_ADC_MODE_MASK GENMASK(1, 0) +/* Current Source/Sink Selection Bits for Sensor Bias */ +#define MCP3564_CONFIG0_CS_SEL_MASK GENMASK(3, 2) +/* Internal clock is selected and AMCLK is present on the analog master clock output pin */ +#define MCP3564_CONFIG0_USE_INT_CLK_OUTPUT_EN 0x03 +/* Internal clock is selected and no clock output is present on the CLK pin */ +#define MCP3564_CONFIG0_USE_INT_CLK 0x02 +/* External digital clock */ +#define MCP3564_CONFIG0_USE_EXT_CLK 0x01 +/* External digital clock (default) */ +#define MCP3564_CONFIG0_USE_EXT_CLK_DEFAULT 0x00 +#define MCP3564_CONFIG0_CLK_SEL_MASK GENMASK(5, 4) +#define MCP3456_CONFIG0_BIT6_DEFAULT BIT(6) +#define MCP3456_CONFIG0_VREF_MASK BIT(7) + +#define MCP3564_CONFIG1_REG 0x02 +#define MCP3564_CONFIG1_OVERSPL_RATIO_MASK GENMASK(5, 2) + +#define MCP3564_CONFIG2_REG 0x03 +#define MCP3564_CONFIG2_AZ_REF_MASK BIT(1) +#define MCP3564_CONFIG2_AZ_MUX_MASK BIT(2) + +#define MCP3564_CONFIG2_HARDWARE_GAIN_MASK GENMASK(5, 3) +#define MCP3564_DEFAULT_HARDWARE_GAIN 0x01 +#define MCP3564_CONFIG2_BOOST_CURRENT_MASK GENMASK(7, 6) + +#define MCP3564_CONFIG3_REG 0x04 +#define MCP3464_CONFIG3_EN_GAINCAL_MASK BIT(0) +#define MCP3464_CONFIG3_EN_OFFCAL_MASK BIT(1) +#define MCP3464_CONFIG3_EN_CRCCOM_MASK BIT(2) +#define MCP3464_CONFIG3_CRC_FORMAT_MASK BIT(3) +/* + * ADC Output Data Format 32-bit (25-bit right justified data + Channel ID): + * CHID[3:0] + SGN extension (4 bits) + 24-bit ADC data. + * It allows overrange with the SGN extension. + */ +#define MCP3464_CONFIG3_DATA_FMT_32B_WITH_CH_ID 3 +/* + * ADC Output Data Format 32-bit (25-bit right justified data): + * SGN extension (8-bit) + 24-bit ADC data. + * It allows overrange with the SGN extension. + */ +#define MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT 2 +/* + * ADC Output Data Format 32-bit (24-bit left justified data): + * 24-bit ADC data + 0x00 (8-bit). + * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000). + */ +#define MCP3464_CONFIG3_DATA_FMT_32B_LEFT_JUSTIFIED 1 +/* + * ADC Output Data Format 24-bit (default ADC coding): + * 24-bit ADC data. + * It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000). + */ +#define MCP3464_CONFIG3_DATA_FMT_24B 0 +#define MCP3464_CONFIG3_DATA_FORMAT_MASK GENMASK(5, 4) + +/* Continuous Conversion mode or continuous conversion cycle in SCAN mode. */ +#define MCP3464_CONFIG3_CONV_MODE_CONTINUOUS 3 +/* + * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘10’ + * (standby) at the end of the conversion or at the end of the conversion cycle in SCAN mode. + */ +#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY 2 +/* + * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘0x’ (ADC + * Shutdown) at the end of the conversion or at the end of the conversion cycle in SCAN + * mode (default). + */ +#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_SHUTDOWN 0 +#define MCP3464_CONFIG3_CONV_MODE_MASK GENMASK(7, 6) + +#define MCP3564_IRQ_REG 0x05 +#define MCP3464_EN_STP_MASK BIT(0) +#define MCP3464_EN_FASTCMD_MASK BIT(1) +#define MCP3464_IRQ_MODE_0_MASK BIT(2) +#define MCP3464_IRQ_MODE_1_MASK BIT(3) +#define MCP3564_POR_STATUS_MASK BIT(4) +#define MCP3564_CRCCFG_STATUS_MASK BIT(5) +#define MCP3564_DATA_READY_MASK BIT(6) + +#define MCP3564_MUX_REG 0x06 +#define MCP3564_MUX_VIN_P_MASK GENMASK(7, 4) +#define MCP3564_MUX_VIN_N_MASK GENMASK(3, 0) +#define MCP3564_MUX_SET(x, y) (FIELD_PREP(MCP3564_MUX_VIN_P_MASK, (x)) | \ + FIELD_PREP(MCP3564_MUX_VIN_N_MASK, (y))) + +#define MCP3564_SCAN_REG 0x07 +#define MCP3564_SCAN_CH_SEL_MASK GENMASK(15, 0) +#define MCP3564_SCAN_CH_SEL_SET(x) FIELD_PREP(MCP3564_SCAN_CH_SEL_MASK, (x)) +#define MCP3564_SCAN_DELAY_TIME_MASK GENMASK(23, 21) +#define MCP3564_SCAN_DELAY_TIME_SET(x) FIELD_PREP(MCP3564_SCAN_DELAY_TIME_MASK, (x)) +#define MCP3564_SCAN_DEFAULT_VALUE 0 + +#define MCP3564_TIMER_REG 0x08 +#define MCP3564_TIMER_DEFAULT_VALUE 0 + +#define MCP3564_OFFSETCAL_REG 0x09 +#define MCP3564_DEFAULT_OFFSETCAL 0 + +#define MCP3564_GAINCAL_REG 0x0A +#define MCP3564_DEFAULT_GAINCAL 0x00800000 + +#define MCP3564_RESERVED_B_REG 0x0B + +#define MCP3564_RESERVED_C_REG 0x0C +#define MCP3564_C_REG_DEFAULT 0x50 +#define MCP3564R_C_REG_DEFAULT 0x30 + +#define MCP3564_LOCK_REG 0x0D +#define MCP3564_LOCK_WRITE_ACCESS_PASSWORD 0xA5 +#define MCP3564_RESERVED_E_REG 0x0E +#define MCP3564_CRCCFG_REG 0x0F + +#define MCP3564_CMD_HW_ADDR_MASK GENMASK(7, 6) +#define MCP3564_CMD_ADDR_MASK GENMASK(5, 2) + +#define MCP3564_HW_ADDR_MASK GENMASK(1, 0) + +#define MCP3564_FASTCMD_START 0x0A +#define MCP3564_FASTCMD_RESET 0x0E + +#define MCP3461_HW_ID 0x0008 +#define MCP3462_HW_ID 0x0009 +#define MCP3464_HW_ID 0x000B + +#define MCP3561_HW_ID 0x000C +#define MCP3562_HW_ID 0x000D +#define MCP3564_HW_ID 0x000F +#define MCP3564_HW_ID_MASK GENMASK(3, 0) + +#define MCP3564R_INT_VREF_MV 2400 + +#define MCP3564_DATA_READY_TIMEOUT_MS 2000 + +#define MCP3564_MAX_PGA 8 +#define MCP3564_MAX_BURNOUT_IDX 4 +#define MCP3564_MAX_CHANNELS 66 + +enum mcp3564_ids { + mcp3461, + mcp3462, + mcp3464, + mcp3561, + mcp3562, + mcp3564, + mcp3461r, + mcp3462r, + mcp3464r, + mcp3561r, + mcp3562r, + mcp3564r, +}; + +enum mcp3564_delay_time { + MCP3564_NO_DELAY, + MCP3564_DELAY_8_DMCLK, + MCP3564_DELAY_16_DMCLK, + MCP3564_DELAY_32_DMCLK, + MCP3564_DELAY_64_DMCLK, + MCP3564_DELAY_128_DMCLK, + MCP3564_DELAY_256_DMCLK, + MCP3564_DELAY_512_DMCLK +}; + +enum mcp3564_adc_conversion_mode { + MCP3564_ADC_MODE_DEFAULT, + MCP3564_ADC_MODE_SHUTDOWN, + MCP3564_ADC_MODE_STANDBY, + MCP3564_ADC_MODE_CONVERSION +}; + +enum mcp3564_adc_bias_current { + MCP3564_BOOST_CURRENT_x0_50, + MCP3564_BOOST_CURRENT_x0_66, + MCP3564_BOOST_CURRENT_x1_00, + MCP3564_BOOST_CURRENT_x2_00 +}; + +enum mcp3564_burnout { + MCP3564_CONFIG0_CS_SEL_0_0_uA, + MCP3564_CONFIG0_CS_SEL_0_9_uA, + MCP3564_CONFIG0_CS_SEL_3_7_uA, + MCP3564_CONFIG0_CS_SEL_15_uA +}; + +enum mcp3564_channel_names { + MCP3564_CH0, + MCP3564_CH1, + MCP3564_CH2, + MCP3564_CH3, + MCP3564_CH4, + MCP3564_CH5, + MCP3564_CH6, + MCP3564_CH7, + MCP3564_AGND, + MCP3564_AVDD, + MCP3564_RESERVED, /* do not use */ + MCP3564_REFIN_POZ, + MCP3564_REFIN_NEG, + MCP3564_TEMP_DIODE_P, + MCP3564_TEMP_DIODE_M, + MCP3564_INTERNAL_VCM, +}; + +enum mcp3564_oversampling { + MCP3564_OVERSAMPLING_RATIO_32, + MCP3564_OVERSAMPLING_RATIO_64, + MCP3564_OVERSAMPLING_RATIO_128, + MCP3564_OVERSAMPLING_RATIO_256, + MCP3564_OVERSAMPLING_RATIO_512, + MCP3564_OVERSAMPLING_RATIO_1024, + MCP3564_OVERSAMPLING_RATIO_2048, + MCP3564_OVERSAMPLING_RATIO_4096, + MCP3564_OVERSAMPLING_RATIO_8192, + MCP3564_OVERSAMPLING_RATIO_16384, + MCP3564_OVERSAMPLING_RATIO_20480, + MCP3564_OVERSAMPLING_RATIO_24576, + MCP3564_OVERSAMPLING_RATIO_40960, + MCP3564_OVERSAMPLING_RATIO_49152, + MCP3564_OVERSAMPLING_RATIO_81920, + MCP3564_OVERSAMPLING_RATIO_98304 +}; + +static const unsigned int mcp3564_oversampling_avail[] = { + [MCP3564_OVERSAMPLING_RATIO_32] = 32, + [MCP3564_OVERSAMPLING_RATIO_64] = 64, + [MCP3564_OVERSAMPLING_RATIO_128] = 128, + [MCP3564_OVERSAMPLING_RATIO_256] = 256, + [MCP3564_OVERSAMPLING_RATIO_512] = 512, + [MCP3564_OVERSAMPLING_RATIO_1024] = 1024, + [MCP3564_OVERSAMPLING_RATIO_2048] = 2048, + [MCP3564_OVERSAMPLING_RATIO_4096] = 4096, + [MCP3564_OVERSAMPLING_RATIO_8192] = 8192, + [MCP3564_OVERSAMPLING_RATIO_16384] = 16384, + [MCP3564_OVERSAMPLING_RATIO_20480] = 20480, + [MCP3564_OVERSAMPLING_RATIO_24576] = 24576, + [MCP3564_OVERSAMPLING_RATIO_40960] = 40960, + [MCP3564_OVERSAMPLING_RATIO_49152] = 49152, + [MCP3564_OVERSAMPLING_RATIO_81920] = 81920, + [MCP3564_OVERSAMPLING_RATIO_98304] = 98304 +}; + +/* + * Current Source/Sink Selection Bits for Sensor Bias (source on VIN+/sink on VIN-) + */ +static const int mcp3564_burnout_avail[][2] = { + [MCP3564_CONFIG0_CS_SEL_0_0_uA] = { 0, 0 }, + [MCP3564_CONFIG0_CS_SEL_0_9_uA] = { 0, 900 }, + [MCP3564_CONFIG0_CS_SEL_3_7_uA] = { 0, 3700 }, + [MCP3564_CONFIG0_CS_SEL_15_uA] = { 0, 15000 } +}; + +/* + * BOOST[1:0]: ADC Bias Current Selection + */ +static const char * const mcp3564_boost_current_avail[] = { + [MCP3564_BOOST_CURRENT_x0_50] = "0.5", + [MCP3564_BOOST_CURRENT_x0_66] = "0.66", + [MCP3564_BOOST_CURRENT_x1_00] = "1", + [MCP3564_BOOST_CURRENT_x2_00] = "2", +}; + +/* + * Calibration bias values + */ +static const int mcp3564_calib_bias[] = { + -8388608, /* min: -2^23 */ + 1, /* step: 1 */ + 8388607 /* max: 2^23 - 1 */ +}; + +/* + * Calibration scale values + * The Gain Error Calibration register (GAINCAL) is an + * unsigned 24-bit register that holds the digital gain error + * calibration value, GAINCAL which could be calculated by + * GAINCAL (V/V) = (GAINCAL[23:0])/8388608 + * The gain error calibration value range in equivalent voltage is [0; 2-2^(-23)] + */ +static const unsigned int mcp3564_calib_scale[] = { + 0, /* min: 0 */ + 1, /* step: 1/8388608 */ + 16777215 /* max: 2 - 2^(-23) */ +}; + +/* Programmable hardware gain x1/3, x1, x2, x4, x8, x16, x32, x64 */ +static const int mcp3564_hwgain_frac[] = { + 3, 10, + 1, 1, + 2, 1, + 4, 1, + 8, 1, + 16, 1, + 32, 1, + 64, 1 +}; + +static const char *mcp3564_channel_labels[2] = { + "burnout_current", "temperature", +}; + +/** + * struct mcp3564_chip_info - chip specific data + * @name: device name + * @num_channels: number of channels + * @resolution: ADC resolution + * @have_vref: does the hardware have an internal voltage reference? + */ +struct mcp3564_chip_info { + const char *name; + unsigned int num_channels; + unsigned int resolution; + bool have_vref; +}; + +/** + * struct mcp3564_state - working data for a ADC device + * @chip_info: chip specific data + * @spi: SPI device structure + * @vref: the regulator device used as a voltage reference in case + * external voltage reference is used + * @vref_mv: voltage reference value in miliVolts + * @lock: synchronize access to driver's state members + * @dev_addr: hardware device address + * @oversampling: the index inside oversampling list of the ADC + * @hwgain: the index inside hardware gain list of the ADC + * @scale_tbls: table with precalculated scale + * @calib_bias: calibration bias value + * @calib_scale: calibration scale value + * @current_boost_mode: the index inside current boost list of the ADC + * @burnout_mode: the index inside current bias list of the ADC + * @auto_zeroing_mux: set if ADC auto-zeroing algorithm is enabled + * @auto_zeroing_ref: set if ADC auto-Zeroing Reference Buffer Setting is enabled + * @have_vref: does the ADC have an internal voltage reference? + * @labels: table with channels labels + */ +struct mcp3564_state { + const struct mcp3564_chip_info *chip_info; + struct spi_device *spi; + struct regulator *vref; + unsigned short vref_mv; + struct mutex lock; /* Synchronize access to driver's state members */ + u8 dev_addr; + enum mcp3564_oversampling oversampling; + unsigned int hwgain; + unsigned int scale_tbls[MCP3564_MAX_PGA][2]; + int calib_bias; + int calib_scale; + unsigned int current_boost_mode; + enum mcp3564_burnout burnout_mode; + bool auto_zeroing_mux; + bool auto_zeroing_ref; + bool have_vref; + const char *labels[MCP3564_MAX_CHANNELS]; +}; + +static inline u8 mcp3564_cmd_write(u8 chip_addr, u8 reg) +{ + return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) | + FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) | + BIT(1); +} + +static inline u8 mcp3564_cmd_read(u8 chip_addr, u8 reg) +{ + return FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, chip_addr) | + FIELD_PREP(MCP3564_CMD_ADDR_MASK, reg) | + BIT(0); +} + +static int mcp3564_read_8bits(struct mcp3564_state *adc, u8 reg, u8 *val) +{ + int ret; + u8 tx_buf; + u8 rx_buf; + + tx_buf = mcp3564_cmd_read(adc->dev_addr, reg); + + ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf), + &rx_buf, sizeof(rx_buf)); + *val = rx_buf; + + return ret; +} + +static int mcp3564_read_16bits(struct mcp3564_state *adc, u8 reg, u16 *val) +{ + int ret; + u8 tx_buf; + __be16 rx_buf; + + tx_buf = mcp3564_cmd_read(adc->dev_addr, reg); + + ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf), + &rx_buf, sizeof(rx_buf)); + *val = be16_to_cpu(rx_buf); + + return ret; +} + +static int mcp3564_read_32bits(struct mcp3564_state *adc, u8 reg, u32 *val) +{ + int ret; + u8 tx_buf; + __be32 rx_buf; + + tx_buf = mcp3564_cmd_read(adc->dev_addr, reg); + + ret = spi_write_then_read(adc->spi, &tx_buf, sizeof(tx_buf), + &rx_buf, sizeof(rx_buf)); + *val = be32_to_cpu(rx_buf); + + return ret; +} + +static int mcp3564_write_8bits(struct mcp3564_state *adc, u8 reg, u8 val) +{ + u8 tx_buf[2]; + + tx_buf[0] = mcp3564_cmd_write(adc->dev_addr, reg); + tx_buf[1] = val; + + return spi_write_then_read(adc->spi, tx_buf, sizeof(tx_buf), NULL, 0); +} + +static int mcp3564_write_24bits(struct mcp3564_state *adc, u8 reg, u32 val) +{ + __be32 val_be; + + val |= (mcp3564_cmd_write(adc->dev_addr, reg) << 24); + val_be = cpu_to_be32(val); + + return spi_write_then_read(adc->spi, &val_be, sizeof(val_be), NULL, 0); +} + +static int mcp3564_fast_cmd(struct mcp3564_state *adc, u8 fast_cmd) +{ + u8 val; + + val = FIELD_PREP(MCP3564_CMD_HW_ADDR_MASK, adc->dev_addr) | + FIELD_PREP(MCP3564_CMD_ADDR_MASK, fast_cmd); + + return spi_write_then_read(adc->spi, &val, 1, NULL, 0); +} + +static int mcp3564_update_8bits(struct mcp3564_state *adc, u8 reg, u32 mask, u8 val) +{ + u8 tmp; + int ret; + + val &= mask; + + ret = mcp3564_read_8bits(adc, reg, &tmp); + if (ret < 0) + return ret; + + tmp &= ~mask; + tmp |= val; + + return mcp3564_write_8bits(adc, reg, tmp); +} + +static int mcp3564_set_current_boost_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int ret; + + dev_dbg(&indio_dev->dev, "%s: %d\n", __func__, mode); + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_BOOST_CURRENT_MASK, + FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, mode)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to configure CONFIG2 register\n"); + else + adc->current_boost_mode = mode; + + mutex_unlock(&adc->lock); + + return ret; +} + +static int mcp3564_get_current_boost_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + + return adc->current_boost_mode; +} + +static const struct iio_enum mcp3564_current_boost_mode_enum = { + .items = mcp3564_boost_current_avail, + .num_items = ARRAY_SIZE(mcp3564_boost_current_avail), + .set = mcp3564_set_current_boost_mode, + .get = mcp3564_get_current_boost_mode, +}; + +static const struct iio_chan_spec_ext_info mcp3564_ext_info[] = { + IIO_ENUM("boost_current_gain", IIO_SHARED_BY_ALL, &mcp3564_current_boost_mode_enum), + { + .name = "boost_current_gain_available", + .shared = IIO_SHARED_BY_ALL, + .read = iio_enum_available_read, + .private = (uintptr_t)&mcp3564_current_boost_mode_enum, + }, + { } +}; + +static ssize_t mcp3564_auto_zeroing_mux_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + + return sysfs_emit(buf, "%d\n", adc->auto_zeroing_mux); +} + +static ssize_t mcp3564_auto_zeroing_mux_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + bool auto_zero; + int ret; + + ret = kstrtobool(buf, &auto_zero); + if (ret) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_MUX_MASK, + FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, auto_zero)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n"); + else + adc->auto_zeroing_mux = auto_zero; + + mutex_unlock(&adc->lock); + + return ret ? ret : len; +} + +static ssize_t mcp3564_auto_zeroing_ref_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + + return sysfs_emit(buf, "%d\n", adc->auto_zeroing_ref); +} + +static ssize_t mcp3564_auto_zeroing_ref_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mcp3564_state *adc = iio_priv(indio_dev); + bool auto_zero; + int ret; + + ret = kstrtobool(buf, &auto_zero); + if (ret) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, MCP3564_CONFIG2_AZ_REF_MASK, + FIELD_PREP(MCP3564_CONFIG2_AZ_REF_MASK, auto_zero)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to update CONFIG2 register\n"); + else + adc->auto_zeroing_ref = auto_zero; + + mutex_unlock(&adc->lock); + + return ret ? ret : len; +} + +static const struct iio_chan_spec mcp3564_channel_template = { + .type = IIO_VOLTAGE, + .indexed = 1, + .differential = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .ext_info = mcp3564_ext_info, +}; + +static const struct iio_chan_spec mcp3564_temp_channel_template = { + .type = IIO_TEMP, + .channel = 0, + .address = ((MCP3564_TEMP_DIODE_P << 4) | MCP3564_TEMP_DIODE_M), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), +}; + +static const struct iio_chan_spec mcp3564_burnout_channel_template = { + .type = IIO_CURRENT, + .output = true, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), +}; + +/* + * Number of channels could be calculated: + * num_channels = single_ended_input + differential_input + temperature + burnout + * Eg. for MCP3561 (only 2 channels available: CH0 and CH1) + * single_ended_input = (CH0 - GND), (CH1 - GND) = 2 + * differential_input = (CH0 - CH1), (CH0 - CH0) = 2 + * num_channels = 2 + 2 + 2 + * Generic formula is: + * num_channels = P^R(Number_of_single_ended_channels, 2) + 2 (temperature + burnout channels) + * P^R(Number_of_single_ended_channels, 2) is Permutations with Replacement of + * Number_of_single_ended_channels taken by 2 + */ +static const struct mcp3564_chip_info mcp3564_chip_infos_tbl[] = { + [mcp3461] = { + .name = "mcp3461", + .num_channels = 6, + .resolution = 16, + .have_vref = false, + }, + [mcp3462] = { + .name = "mcp3462", + .num_channels = 18, + .resolution = 16, + .have_vref = false, + }, + [mcp3464] = { + .name = "mcp3464", + .num_channels = 66, + .resolution = 16, + .have_vref = false, + }, + [mcp3561] = { + .name = "mcp3561", + .num_channels = 6, + .resolution = 24, + .have_vref = false, + }, + [mcp3562] = { + .name = "mcp3562", + .num_channels = 18, + .resolution = 24, + .have_vref = false, + }, + [mcp3564] = { + .name = "mcp3564", + .num_channels = 66, + .resolution = 24, + .have_vref = false, + }, + [mcp3461r] = { + .name = "mcp3461r", + .num_channels = 6, + .resolution = 16, + .have_vref = false, + }, + [mcp3462r] = { + .name = "mcp3462r", + .num_channels = 18, + .resolution = 16, + .have_vref = true, + }, + [mcp3464r] = { + .name = "mcp3464r", + .num_channels = 66, + .resolution = 16, + .have_vref = true, + }, + [mcp3561r] = { + .name = "mcp3561r", + .num_channels = 6, + .resolution = 24, + .have_vref = true, + }, + [mcp3562r] = { + .name = "mcp3562r", + .num_channels = 18, + .resolution = 24, + .have_vref = true, + }, + [mcp3564r] = { + .name = "mcp3564r", + .num_channels = 66, + .resolution = 24, + .have_vref = true, + }, +}; + +static int mcp3564_read_single_value(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, + int *val) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int ret; + u8 tmp; + int ret_read = 0; + + ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, channel->address); + if (ret) + return ret; + + /* Start ADC Conversion using fast command (overwrites ADC_MODE[1:0] = 11) */ + ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_START); + if (ret) + return ret; + + /* + * Check if the conversion is ready. If not, wait a little bit, and + * in case of timeout exit with an error. + */ + ret = read_poll_timeout(mcp3564_read_8bits, ret_read, + ret_read || !(tmp & MCP3564_DATA_READY_MASK), + 20000, MCP3564_DATA_READY_TIMEOUT_MS * 1000, true, + adc, MCP3564_IRQ_REG, &tmp); + + /* failed to read status register */ + if (ret_read) + return ret_read; + + if (ret) + return ret; + + if (tmp & MCP3564_DATA_READY_MASK) + /* failing to finish conversion */ + return -EBUSY; + + return mcp3564_read_32bits(adc, MCP3564_ADCDATA_REG, val); +} + +static int mcp3564_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, + const int **vals, int *type, + int *length, long mask) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (!channel->output) + return -EINVAL; + + *vals = mcp3564_burnout_avail[0]; + *length = ARRAY_SIZE(mcp3564_burnout_avail) * 2; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = mcp3564_oversampling_avail; + *length = ARRAY_SIZE(mcp3564_oversampling_avail); + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (int *)adc->scale_tbls; + *length = ARRAY_SIZE(adc->scale_tbls) * 2; + *type = IIO_VAL_INT_PLUS_NANO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_CALIBBIAS: + *vals = mcp3564_calib_bias; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + case IIO_CHAN_INFO_CALIBSCALE: + *vals = mcp3564_calib_scale; + *type = IIO_VAL_INT; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +static int mcp3564_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, + int *val, int *val2, long mask) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (channel->output) { + mutex_lock(&adc->lock); + *val = mcp3564_burnout_avail[adc->burnout_mode][0]; + *val2 = mcp3564_burnout_avail[adc->burnout_mode][1]; + mutex_unlock(&adc->lock); + return IIO_VAL_INT_PLUS_MICRO; + } + + ret = mcp3564_read_single_value(indio_dev, channel, val); + if (ret) + return -EINVAL; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + mutex_lock(&adc->lock); + *val = adc->scale_tbls[adc->hwgain][0]; + *val2 = adc->scale_tbls[adc->hwgain][1]; + mutex_unlock(&adc->lock); + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = mcp3564_oversampling_avail[adc->oversampling]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + *val = adc->calib_bias; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + *val = adc->calib_scale; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int mcp3564_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long info) +{ + switch (info) { + case IIO_CHAN_INFO_RAW: + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_CALIBBIAS: + case IIO_CHAN_INFO_CALIBSCALE: + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static int mcp3564_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int val, + int val2, long mask) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + int tmp; + unsigned int hwgain; + enum mcp3564_burnout burnout; + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (!channel->output) + return -EINVAL; + + for (burnout = 0; burnout < MCP3564_MAX_BURNOUT_IDX; burnout++) + if (val == mcp3564_burnout_avail[burnout][0] && + val2 == mcp3564_burnout_avail[burnout][1]) + break; + + if (burnout == MCP3564_MAX_BURNOUT_IDX) + return -EINVAL; + + if (burnout == adc->burnout_mode) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG0_REG, + MCP3564_CONFIG0_CS_SEL_MASK, + FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, burnout)); + + if (ret) + dev_err(&indio_dev->dev, "Failed to configure burnout current\n"); + else + adc->burnout_mode = burnout; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_CALIBBIAS: + if (val < mcp3564_calib_bias[0] && val > mcp3564_calib_bias[2]) + return -EINVAL; + + mutex_lock(&adc->lock); + ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, val); + if (!ret) + adc->calib_bias = val; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_CALIBSCALE: + if (val < mcp3564_calib_scale[0] && val > mcp3564_calib_scale[2]) + return -EINVAL; + + if (adc->calib_scale == val) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, val); + if (!ret) + adc->calib_scale = val; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val < 0) + return -EINVAL; + + tmp = find_closest(val, mcp3564_oversampling_avail, + ARRAY_SIZE(mcp3564_oversampling_avail)); + + if (adc->oversampling == tmp) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG1_REG, + MCP3564_CONFIG1_OVERSPL_RATIO_MASK, + FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK, + adc->oversampling)); + if (!ret) + adc->oversampling = tmp; + mutex_unlock(&adc->lock); + return ret; + case IIO_CHAN_INFO_SCALE: + for (hwgain = 0; hwgain < MCP3564_MAX_PGA; hwgain++) + if (val == adc->scale_tbls[hwgain][0] && + val2 == adc->scale_tbls[hwgain][1]) + break; + + if (hwgain == MCP3564_MAX_PGA) + return -EINVAL; + + if (hwgain == adc->hwgain) + return ret; + + mutex_lock(&adc->lock); + ret = mcp3564_update_8bits(adc, MCP3564_CONFIG2_REG, + MCP3564_CONFIG2_HARDWARE_GAIN_MASK, + FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, hwgain)); + if (!ret) + adc->hwgain = hwgain; + + mutex_unlock(&adc->lock); + return ret; + default: + return -EINVAL; + } +} + +static int mcp3564_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, char *label) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + + return sprintf(label, "%s\n", adc->labels[chan->scan_index]); +} + +static int mcp3564_parse_fw_children(struct iio_dev *indio_dev) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + struct device *dev = &adc->spi->dev; + struct iio_chan_spec *channels; + struct fwnode_handle *child; + struct iio_chan_spec chanspec = mcp3564_channel_template; + struct iio_chan_spec temp_chanspec = mcp3564_temp_channel_template; + struct iio_chan_spec burnout_chanspec = mcp3564_burnout_channel_template; + int chan_idx = 0; + unsigned int num_ch; + u32 inputs[2]; + const char *node_name; + const char *label; + int ret; + + num_ch = device_get_child_node_count(dev); + if (num_ch == 0) + return dev_err_probe(&indio_dev->dev, -ENODEV, + "FW has no channels defined\n"); + + /* Reserve space for burnout and temperature channel */ + num_ch += 2; + + if (num_ch > adc->chip_info->num_channels) + return dev_err_probe(dev, -EINVAL, "Too many channels %d > %d\n", + num_ch, adc->chip_info->num_channels); + + channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL); + if (!channels) + return dev_err_probe(dev, -ENOMEM, "Can't allocate memory\n"); + + device_for_each_child_node(dev, child) { + node_name = fwnode_get_name(child); + + if (fwnode_property_present(child, "diff-channels")) { + ret = fwnode_property_read_u32_array(child, + "diff-channels", + inputs, + ARRAY_SIZE(inputs)); + chanspec.differential = 1; + } else { + ret = fwnode_property_read_u32(child, "reg", &inputs[0]); + + chanspec.differential = 0; + inputs[1] = MCP3564_AGND; + } + if (ret) { + fwnode_handle_put(child); + return ret; + } + + if (inputs[0] > MCP3564_INTERNAL_VCM || + inputs[1] > MCP3564_INTERNAL_VCM) { + fwnode_handle_put(child); + return dev_err_probe(&indio_dev->dev, -EINVAL, + "Channel index > %d, for %s\n", + MCP3564_INTERNAL_VCM + 1, + node_name); + } + + chanspec.address = (inputs[0] << 4) | inputs[1]; + chanspec.channel = inputs[0]; + chanspec.channel2 = inputs[1]; + chanspec.scan_index = chan_idx; + + if (fwnode_property_present(child, "label")) { + fwnode_property_read_string(child, "label", &label); + adc->labels[chan_idx] = label; + } + + channels[chan_idx] = chanspec; + chan_idx++; + } + + /* Add burnout current channel */ + burnout_chanspec.scan_index = chan_idx; + channels[chan_idx] = burnout_chanspec; + adc->labels[chan_idx] = mcp3564_channel_labels[0]; + chanspec.scan_index = chan_idx; + chan_idx++; + + /* Add temperature channel */ + temp_chanspec.scan_index = chan_idx; + channels[chan_idx] = temp_chanspec; + adc->labels[chan_idx] = mcp3564_channel_labels[1]; + chan_idx++; + + indio_dev->num_channels = chan_idx; + indio_dev->channels = channels; + + return 0; +} + +static void mcp3564_disable_reg(void *reg) +{ + regulator_disable(reg); +} + +static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc) +{ + unsigned int pow = adc->chip_info->resolution - 1; + int ref; + unsigned int i; + int tmp0; + u64 tmp1; + + for (i = 0; i < MCP3564_MAX_PGA; i++) { + ref = adc->vref_mv; + tmp1 = ((u64)ref * NANO) >> pow; + div_u64_rem(tmp1, NANO, &tmp0); + + tmp1 = tmp1 * mcp3564_hwgain_frac[(2 * i) + 1]; + tmp0 = (int)div_u64(tmp1, mcp3564_hwgain_frac[2 * i]); + + adc->scale_tbls[i][1] = tmp0; + } +} + +static int mcp3564_config(struct iio_dev *indio_dev) +{ + struct mcp3564_state *adc = iio_priv(indio_dev); + struct device *dev = &adc->spi->dev; + const struct spi_device_id *dev_id; + u8 tmp_reg; + u16 tmp_u16; + enum mcp3564_ids ids; + int ret = 0; + unsigned int tmp = 0x01; + bool err = true; + + /* + * The address is set on a per-device basis by fuses in the factory, + * configured on request. If not requested, the fuses are set for 0x1. + * The device address is part of the device markings to avoid + * potential confusion. This address is coded on two bits, so four possible + * addresses are available when multiple devices are present on the same + * SPI bus with only one Chip Select line for all devices. + */ + device_property_read_u32(dev, "microchip,hw-device-address", &tmp); + + if (tmp > 3) { + dev_err_probe(dev, tmp, + "invalid device address. Must be in range 0-3.\n"); + return -EINVAL; + } + + adc->dev_addr = FIELD_GET(MCP3564_HW_ADDR_MASK, tmp); + + dev_dbg(dev, "use HW device address %i\n", adc->dev_addr); + + ret = mcp3564_read_8bits(adc, MCP3564_RESERVED_C_REG, &tmp_reg); + if (ret < 0) + return ret; + + switch (tmp_reg) { + case MCP3564_C_REG_DEFAULT: + adc->have_vref = false; + break; + case MCP3564R_C_REG_DEFAULT: + adc->have_vref = true; + break; + default: + dev_info(dev, "Unknown chip found: %d\n", tmp_reg); + err = true; + } + + if (!err) { + ret = mcp3564_read_16bits(adc, MCP3564_RESERVED_E_REG, &tmp_u16); + if (ret < 0) + return ret; + + switch (tmp_u16 & MCP3564_HW_ID_MASK) { + case MCP3461_HW_ID: + if (adc->have_vref) + ids = mcp3461r; + else + ids = mcp3461; + break; + case MCP3462_HW_ID: + if (adc->have_vref) + ids = mcp3462r; + else + ids = mcp3462; + break; + case MCP3464_HW_ID: + if (adc->have_vref) + ids = mcp3464r; + else + ids = mcp3464; + break; + case MCP3561_HW_ID: + if (adc->have_vref) + ids = mcp3561r; + else + ids = mcp3561; + break; + case MCP3562_HW_ID: + if (adc->have_vref) + ids = mcp3562r; + else + ids = mcp3562; + break; + case MCP3564_HW_ID: + if (adc->have_vref) + ids = mcp3564r; + else + ids = mcp3564; + break; + default: + dev_info(dev, "Unknown chip found: %d\n", tmp_u16); + err = true; + } + } + + if (err) { + /* + * If failed to identify the hardware based on internal registers, + * try using fallback compatible in device tree to deal with some newer part number. + */ + adc->chip_info = spi_get_device_match_data(adc->spi); + if (!adc->chip_info) { + dev_id = spi_get_device_id(adc->spi); + adc->chip_info = (const struct mcp3564_chip_info *)dev_id->driver_data; + } + + adc->have_vref = adc->chip_info->have_vref; + } else { + adc->chip_info = &mcp3564_chip_infos_tbl[ids]; + } + + dev_dbg(dev, "Found %s chip\n", adc->chip_info->name); + + adc->vref = devm_regulator_get_optional(dev, "vref"); + if (IS_ERR(adc->vref)) { + if (PTR_ERR(adc->vref) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(adc->vref), + "failed to get regulator\n"); + + /* Check if chip has internal vref */ + if (!adc->have_vref) + return dev_err_probe(dev, PTR_ERR(adc->vref), + "Unknown Vref\n"); + adc->vref = NULL; + dev_dbg(dev, "%s: Using internal Vref\n", __func__); + } else { + ret = regulator_enable(adc->vref); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, mcp3564_disable_reg, + adc->vref); + if (ret) + return ret; + + dev_dbg(dev, "%s: Using External Vref\n", __func__); + + ret = regulator_get_voltage(adc->vref); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to read vref regulator\n"); + + adc->vref_mv = ret / MILLI; + } + + ret = mcp3564_parse_fw_children(indio_dev); + if (ret) + return ret; + + /* + * Command sequence that ensures a recovery with the desired settings + * in any cases of loss-of-power scenario (Full Chip Reset): + * - Write LOCK register to 0xA5 + * - Write IRQ register to 0x03 + * - Send "Device Full Reset" fast command + * - Wait 1ms for "Full Reset" to complete + */ + ret = mcp3564_write_8bits(adc, MCP3564_LOCK_REG, MCP3564_LOCK_WRITE_ACCESS_PASSWORD); + if (ret) + return ret; + + ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG, 0x03); + if (ret) + return ret; + + ret = mcp3564_fast_cmd(adc, MCP3564_FASTCMD_RESET); + if (ret) + return ret; + + /* + * After Full reset wait some time to be able to fully reset the part and place + * it back in a default configuration. + * From datasheet: POR (Power On Reset Time) is ~1us + * 1ms should be enough. + */ + mdelay(1); + + /* set a gain of 1x for GAINCAL */ + ret = mcp3564_write_24bits(adc, MCP3564_GAINCAL_REG, MCP3564_DEFAULT_GAINCAL); + if (ret) + return ret; + + adc->calib_scale = MCP3564_DEFAULT_GAINCAL; + + ret = mcp3564_write_24bits(adc, MCP3564_OFFSETCAL_REG, MCP3564_DEFAULT_OFFSETCAL); + if (ret) + return ret; + + ret = mcp3564_write_24bits(adc, MCP3564_TIMER_REG, MCP3564_TIMER_DEFAULT_VALUE); + if (ret) + return ret; + + ret = mcp3564_write_24bits(adc, MCP3564_SCAN_REG, + MCP3564_SCAN_DELAY_TIME_SET(MCP3564_NO_DELAY) | + MCP3564_SCAN_CH_SEL_SET(MCP3564_SCAN_DEFAULT_VALUE)); + if (ret) + return ret; + + ret = mcp3564_write_8bits(adc, MCP3564_MUX_REG, MCP3564_MUX_SET(MCP3564_CH0, MCP3564_CH1)); + if (ret) + return ret; + + ret = mcp3564_write_8bits(adc, MCP3564_IRQ_REG, + FIELD_PREP(MCP3464_EN_FASTCMD_MASK, 1) | + FIELD_PREP(MCP3464_EN_STP_MASK, 1)); + if (ret) + return ret; + + tmp_reg = FIELD_PREP(MCP3464_CONFIG3_CONV_MODE_MASK, + MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY); + tmp_reg |= FIELD_PREP(MCP3464_CONFIG3_DATA_FORMAT_MASK, + MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT); + tmp_reg |= MCP3464_CONFIG3_EN_OFFCAL_MASK; + tmp_reg |= MCP3464_CONFIG3_EN_GAINCAL_MASK; + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG3_REG, tmp_reg); + if (ret) + return ret; + + tmp_reg = FIELD_PREP(MCP3564_CONFIG2_BOOST_CURRENT_MASK, MCP3564_BOOST_CURRENT_x1_00); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_HARDWARE_GAIN_MASK, 0x01); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG2_AZ_MUX_MASK, 1); + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG2_REG, tmp_reg); + if (ret) + return ret; + + adc->hwgain = 0x01; + adc->auto_zeroing_mux = true; + adc->auto_zeroing_ref = false; + adc->current_boost_mode = MCP3564_BOOST_CURRENT_x1_00; + + tmp_reg = FIELD_PREP(MCP3564_CONFIG1_OVERSPL_RATIO_MASK, MCP3564_OVERSAMPLING_RATIO_98304); + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG1_REG, tmp_reg); + if (ret) + return ret; + + adc->oversampling = MCP3564_OVERSAMPLING_RATIO_98304; + + tmp_reg = FIELD_PREP(MCP3564_CONFIG0_ADC_MODE_MASK, MCP3564_ADC_MODE_STANDBY); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CS_SEL_MASK, MCP3564_CONFIG0_CS_SEL_0_0_uA); + tmp_reg |= FIELD_PREP(MCP3564_CONFIG0_CLK_SEL_MASK, MCP3564_CONFIG0_USE_INT_CLK); + tmp_reg |= MCP3456_CONFIG0_BIT6_DEFAULT; + + if (!adc->vref) { + tmp_reg |= FIELD_PREP(MCP3456_CONFIG0_VREF_MASK, 1); + adc->vref_mv = MCP3564R_INT_VREF_MV; + } + + ret = mcp3564_write_8bits(adc, MCP3564_CONFIG0_REG, tmp_reg); + + adc->burnout_mode = MCP3564_CONFIG0_CS_SEL_0_0_uA; + + return ret; +} + +static IIO_DEVICE_ATTR(auto_zeroing_ref_enable, 0644, + mcp3564_auto_zeroing_ref_show, + mcp3564_auto_zeroing_ref_store, 0); + +static IIO_DEVICE_ATTR(auto_zeroing_mux_enable, 0644, + mcp3564_auto_zeroing_mux_show, + mcp3564_auto_zeroing_mux_store, 0); + +static struct attribute *mcp3564_attributes[] = { + &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr, + NULL +}; + +static struct attribute *mcp3564r_attributes[] = { + &iio_dev_attr_auto_zeroing_mux_enable.dev_attr.attr, + &iio_dev_attr_auto_zeroing_ref_enable.dev_attr.attr, + NULL +}; + +static struct attribute_group mcp3564_attribute_group = { + .attrs = mcp3564_attributes, +}; + +static struct attribute_group mcp3564r_attribute_group = { + .attrs = mcp3564r_attributes, +}; + +static const struct iio_info mcp3564_info = { + .read_raw = mcp3564_read_raw, + .read_avail = mcp3564_read_avail, + .write_raw = mcp3564_write_raw, + .write_raw_get_fmt = mcp3564_write_raw_get_fmt, + .read_label = mcp3564_read_label, + .attrs = &mcp3564_attribute_group, +}; + +static const struct iio_info mcp3564r_info = { + .read_raw = mcp3564_read_raw, + .read_avail = mcp3564_read_avail, + .write_raw = mcp3564_write_raw, + .write_raw_get_fmt = mcp3564_write_raw_get_fmt, + .read_label = mcp3564_read_label, + .attrs = &mcp3564r_attribute_group, +}; + +static int mcp3564_probe(struct spi_device *spi) +{ + int ret; + struct iio_dev *indio_dev; + struct mcp3564_state *adc; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->spi = spi; + + dev_dbg(&spi->dev, "%s: probe(spi = 0x%p)\n", __func__, spi); + + /* + * Do any chip specific initialization, e.g: + * read/write some registers + * enable/disable certain channels + * change the sampling rate to the requested value + */ + ret = mcp3564_config(indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Can't configure MCP356X device\n"); + + dev_dbg(&spi->dev, "%s: Vref (mV): %d\n", __func__, adc->vref_mv); + + mcp3564_fill_scale_tbls(adc); + + indio_dev->name = adc->chip_info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + + if (!adc->vref) + indio_dev->info = &mcp3564r_info; + else + indio_dev->info = &mcp3564_info; + + mutex_init(&adc->lock); + + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "Can't register IIO device\n"); + + return 0; +} + +static const struct of_device_id mcp3564_dt_ids[] = { + { .compatible = "microchip,mcp3461", .data = &mcp3564_chip_infos_tbl[mcp3461] }, + { .compatible = "microchip,mcp3462", .data = &mcp3564_chip_infos_tbl[mcp3462] }, + { .compatible = "microchip,mcp3464", .data = &mcp3564_chip_infos_tbl[mcp3464] }, + { .compatible = "microchip,mcp3561", .data = &mcp3564_chip_infos_tbl[mcp3561] }, + { .compatible = "microchip,mcp3562", .data = &mcp3564_chip_infos_tbl[mcp3562] }, + { .compatible = "microchip,mcp3564", .data = &mcp3564_chip_infos_tbl[mcp3564] }, + { .compatible = "microchip,mcp3461r", .data = &mcp3564_chip_infos_tbl[mcp3461r] }, + { .compatible = "microchip,mcp3462r", .data = &mcp3564_chip_infos_tbl[mcp3462r] }, + { .compatible = "microchip,mcp3464r", .data = &mcp3564_chip_infos_tbl[mcp3464r] }, + { .compatible = "microchip,mcp3561r", .data = &mcp3564_chip_infos_tbl[mcp3561r] }, + { .compatible = "microchip,mcp3562r", .data = &mcp3564_chip_infos_tbl[mcp3562r] }, + { .compatible = "microchip,mcp3564r", .data = &mcp3564_chip_infos_tbl[mcp3564r] }, + { } +}; +MODULE_DEVICE_TABLE(of, mcp3564_dt_ids); + +static const struct spi_device_id mcp3564_id[] = { + { "mcp3461", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461] }, + { "mcp3462", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462] }, + { "mcp3464", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464] }, + { "mcp3561", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561] }, + { "mcp3562", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562] }, + { "mcp3564", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564] }, + { "mcp3461r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3461r] }, + { "mcp3462r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3462r] }, + { "mcp3464r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3464r] }, + { "mcp3561r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3561r] }, + { "mcp3562r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3562r] }, + { "mcp3564r", (kernel_ulong_t)&mcp3564_chip_infos_tbl[mcp3564r] }, + { } +}; +MODULE_DEVICE_TABLE(spi, mcp3564_id); + +static struct spi_driver mcp3564_driver = { + .driver = { + .name = "mcp3564", + .of_match_table = mcp3564_dt_ids, + }, + .probe = mcp3564_probe, + .id_table = mcp3564_id, +}; + +module_spi_driver(mcp3564_driver); + +MODULE_AUTHOR("Marius Cristea <marius.cristea@microchip.com>"); +MODULE_DESCRIPTION("Microchip MCP346x/MCP346xR and MCP356x/MCP346xR ADCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index 974c5bd923a6..d864558bc087 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -29,11 +29,11 @@ #define MCP3911_REG_MOD 0x06 #define MCP3911_REG_PHASE 0x07 #define MCP3911_REG_GAIN 0x09 -#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * ch) -#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * ch) & MCP3911_GAIN_MASK(ch)) +#define MCP3911_GAIN_MASK(ch) (GENMASK(2, 0) << 3 * (ch)) +#define MCP3911_GAIN_VAL(ch, val) ((val << 3 * (ch)) & MCP3911_GAIN_MASK(ch)) #define MCP3911_REG_STATUSCOM 0x0a -#define MCP3911_STATUSCOM_DRHIZ BIT(12) +#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) @@ -51,8 +51,8 @@ #define MCP3911_REG_GAINCAL_CH1 0x17 #define MCP3911_REG_VREFCAL 0x1a -#define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3) -#define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6) +#define MCP3911_CHANNEL(ch) (MCP3911_REG_CHANNEL0 + (ch) * 3) +#define MCP3911_OFFCAL(ch) (MCP3911_REG_OFFCAL_CH0 + (ch) * 6) /* Internal voltage reference in mV */ #define MCP3911_INT_VREF_MV 1200 @@ -61,12 +61,56 @@ #define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 6) | (0 << 0)) & 0xff) #define MCP3911_REG_MASK GENMASK(4, 1) -#define MCP3911_NUM_CHANNELS 2 #define MCP3911_NUM_SCALES 6 +/* Registers compatible with MCP3910 */ +#define MCP3910_REG_STATUSCOM 0x0c +#define MCP3910_STATUSCOM_READ GENMASK(23, 22) +#define MCP3910_STATUSCOM_DRHIZ BIT(20) + +#define MCP3910_REG_GAIN 0x0b + +#define MCP3910_REG_CONFIG0 0x0d +#define MCP3910_CONFIG0_EN_OFFCAL BIT(23) +#define MCP3910_CONFIG0_OSR GENMASK(15, 13) + +#define MCP3910_REG_CONFIG1 0x0e +#define MCP3910_CONFIG1_CLKEXT BIT(6) +#define MCP3910_CONFIG1_VREFEXT BIT(7) + +#define MCP3910_REG_OFFCAL_CH0 0x0f +#define MCP3910_OFFCAL(ch) (MCP3910_REG_OFFCAL_CH0 + (ch) * 6) + +/* Maximal number of channels used by the MCP39XX family */ +#define MCP39XX_MAX_NUM_CHANNELS 8 + static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 }; static u32 mcp3911_scale_table[MCP3911_NUM_SCALES][2]; +enum mcp3911_id { + MCP3910, + MCP3911, + MCP3912, + MCP3913, + MCP3914, + MCP3918, + MCP3919, +}; + +struct mcp3911; +struct mcp3911_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; + + int (*config)(struct mcp3911 *adc); + int (*get_osr)(struct mcp3911 *adc, u32 *val); + int (*set_osr)(struct mcp3911 *adc, u32 val); + int (*enable_offset)(struct mcp3911 *adc, bool enable); + int (*get_offset)(struct mcp3911 *adc, int channel, int *val); + int (*set_offset)(struct mcp3911 *adc, int channel, int val); + int (*set_scale)(struct mcp3911 *adc, int channel, u32 val); +}; + struct mcp3911 { struct spi_device *spi; struct mutex lock; @@ -74,14 +118,15 @@ struct mcp3911 { struct clk *clki; u32 dev_addr; struct iio_trigger *trig; - u32 gain[MCP3911_NUM_CHANNELS]; + u32 gain[MCP39XX_MAX_NUM_CHANNELS]; + const struct mcp3911_chip_info *chip; struct { - u32 channels[MCP3911_NUM_CHANNELS]; + u32 channels[MCP39XX_MAX_NUM_CHANNELS]; s64 ts __aligned(8); } scan; u8 tx_buf __aligned(IIO_DMA_MINALIGN); - u8 rx_buf[MCP3911_NUM_CHANNELS * 3]; + u8 rx_buf[MCP39XX_MAX_NUM_CHANNELS * 3]; }; static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len) @@ -111,8 +156,7 @@ static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len) return spi_write(adc->spi, &val, len + 1); } -static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, - u32 val, u8 len) +static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len) { u32 tmp; int ret; @@ -126,9 +170,115 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, return mcp3911_write(adc, reg, val, len); } +static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable) +{ + unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL; + unsigned int value = enable ? mask : 0; + + return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, value, 3); +} + +static int mcp3910_get_offset(struct mcp3911 *adc, int channel, int *val) +{ + return mcp3911_read(adc, MCP3910_OFFCAL(channel), val, 3); +} + +static int mcp3910_set_offset(struct mcp3911 *adc, int channel, int val) +{ + int ret; + + ret = mcp3911_write(adc, MCP3910_OFFCAL(channel), val, 3); + if (ret) + return ret; + + return adc->chip->enable_offset(adc, 1); +} + +static int mcp3911_enable_offset(struct mcp3911 *adc, bool enable) +{ + unsigned int mask = MCP3911_STATUSCOM_EN_OFFCAL; + unsigned int value = enable ? mask : 0; + + return mcp3911_update(adc, MCP3911_REG_STATUSCOM, mask, value, 2); +} + +static int mcp3911_get_offset(struct mcp3911 *adc, int channel, int *val) +{ + return mcp3911_read(adc, MCP3911_OFFCAL(channel), val, 3); +} + +static int mcp3911_set_offset(struct mcp3911 *adc, int channel, int val) +{ + int ret; + + ret = mcp3911_write(adc, MCP3911_OFFCAL(channel), val, 3); + if (ret) + return ret; + + return adc->chip->enable_offset(adc, 1); +} + +static int mcp3910_get_osr(struct mcp3911 *adc, u32 *val) +{ + int ret; + unsigned int osr; + + ret = mcp3911_read(adc, MCP3910_REG_CONFIG0, val, 3); + if (ret) + return ret; + + osr = FIELD_GET(MCP3910_CONFIG0_OSR, *val); + *val = 32 << osr; + return 0; +} + +static int mcp3910_set_osr(struct mcp3911 *adc, u32 val) +{ + unsigned int osr = FIELD_PREP(MCP3910_CONFIG0_OSR, val); + unsigned int mask = MCP3910_CONFIG0_OSR; + + return mcp3911_update(adc, MCP3910_REG_CONFIG0, mask, osr, 3); +} + +static int mcp3911_set_osr(struct mcp3911 *adc, u32 val) +{ + unsigned int osr = FIELD_PREP(MCP3911_CONFIG_OSR, val); + unsigned int mask = MCP3911_CONFIG_OSR; + + return mcp3911_update(adc, MCP3911_REG_CONFIG, mask, osr, 2); +} + +static int mcp3911_get_osr(struct mcp3911 *adc, u32 *val) +{ + int ret; + unsigned int osr; + + ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2); + if (ret) + return ret; + + osr = FIELD_GET(MCP3911_CONFIG_OSR, *val); + *val = 32 << osr; + return ret; +} + +static int mcp3910_set_scale(struct mcp3911 *adc, int channel, u32 val) +{ + return mcp3911_update(adc, MCP3910_REG_GAIN, + MCP3911_GAIN_MASK(channel), + MCP3911_GAIN_VAL(channel, val), 3); +} + +static int mcp3911_set_scale(struct mcp3911 *adc, int channel, u32 val) +{ + return mcp3911_update(adc, MCP3911_REG_GAIN, + MCP3911_GAIN_MASK(channel), + MCP3911_GAIN_VAL(channel, val), 1); +} + static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) + struct iio_chan_spec const *chan, + long mask) { switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -141,9 +291,9 @@ static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev, } static int mcp3911_read_avail(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - const int **vals, int *type, int *length, - long info) + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) { switch (info) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: @@ -182,20 +332,18 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_OFFSET: - ret = mcp3911_read(adc, - MCP3911_OFFCAL(channel->channel), val, 3); + + ret = adc->chip->get_offset(adc, channel->channel, val); if (ret) goto out; ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2); + ret = adc->chip->get_osr(adc, val); if (ret) goto out; - *val = FIELD_GET(MCP3911_CONFIG_OSR, *val); - *val = 32 << *val; ret = IIO_VAL_INT; break; @@ -212,8 +360,8 @@ out: } static int mcp3911_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *channel, int val, - int val2, long mask) + struct iio_chan_spec const *channel, int val, + int val2, long mask) { struct mcp3911 *adc = iio_priv(indio_dev); int ret = -EINVAL; @@ -223,12 +371,10 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: for (int i = 0; i < MCP3911_NUM_SCALES; i++) { if (val == mcp3911_scale_table[i][0] && - val2 == mcp3911_scale_table[i][1]) { + val2 == mcp3911_scale_table[i][1]) { adc->gain[channel->channel] = BIT(i); - ret = mcp3911_update(adc, MCP3911_REG_GAIN, - MCP3911_GAIN_MASK(channel->channel), - MCP3911_GAIN_VAL(channel->channel, i), 1); + ret = adc->chip->set_scale(adc, channel->channel, i); } } break; @@ -238,24 +384,13 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev, goto out; } - /* Write offset */ - ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val, - 3); - if (ret) - goto out; - - /* Enable offset*/ - ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, - MCP3911_STATUSCOM_EN_OFFCAL, - MCP3911_STATUSCOM_EN_OFFCAL, 2); + ret = adc->chip->set_offset(adc, channel->channel, val); break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: for (int i = 0; i < ARRAY_SIZE(mcp3911_osr_table); i++) { if (val == mcp3911_osr_table[i]) { - val = FIELD_PREP(MCP3911_CONFIG_OSR, i); - ret = mcp3911_update(adc, MCP3911_REG_CONFIG, MCP3911_CONFIG_OSR, - val, 2); + ret = adc->chip->set_osr(adc, i); break; } } @@ -269,6 +404,7 @@ out: static int mcp3911_calc_scale_table(struct mcp3911 *adc) { + struct device *dev = &adc->spi->dev; u32 ref = MCP3911_INT_VREF_MV; u32 div; int ret; @@ -277,10 +413,7 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc) if (adc->vref) { ret = regulator_get_voltage(adc->vref); if (ret < 0) { - dev_err(&adc->spi->dev, - "failed to get vref voltage: %d\n", - ret); - return ret; + return dev_err_probe(dev, ret, "failed to get vref voltage\n"); } ref = ret / 1000; @@ -326,24 +459,73 @@ static int mcp3911_calc_scale_table(struct mcp3911 *adc) }, \ } +static const struct iio_chan_spec mcp3910_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + static const struct iio_chan_spec mcp3911_channels[] = { MCP3911_CHAN(0), MCP3911_CHAN(1), IIO_CHAN_SOFT_TIMESTAMP(2), }; +static const struct iio_chan_spec mcp3912_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + MCP3911_CHAN(3), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct iio_chan_spec mcp3913_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + MCP3911_CHAN(3), + MCP3911_CHAN(4), + MCP3911_CHAN(5), + IIO_CHAN_SOFT_TIMESTAMP(6), +}; + +static const struct iio_chan_spec mcp3914_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + MCP3911_CHAN(3), + MCP3911_CHAN(4), + MCP3911_CHAN(5), + MCP3911_CHAN(6), + MCP3911_CHAN(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_chan_spec mcp3918_channels[] = { + MCP3911_CHAN(0), + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct iio_chan_spec mcp3919_channels[] = { + MCP3911_CHAN(0), + MCP3911_CHAN(1), + MCP3911_CHAN(2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + static irqreturn_t mcp3911_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct mcp3911 *adc = iio_priv(indio_dev); + struct device *dev = &adc->spi->dev; struct spi_transfer xfer[] = { { .tx_buf = &adc->tx_buf, .len = 1, }, { .rx_buf = adc->rx_buf, - .len = sizeof(adc->rx_buf), + .len = (adc->chip->num_channels - 1) * 3, }, }; int scan_index; @@ -354,8 +536,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p) adc->tx_buf = MCP3911_REG_READ(MCP3911_CHANNEL(0), adc->dev_addr); ret = spi_sync_transfer(adc->spi, xfer, ARRAY_SIZE(xfer)); if (ret < 0) { - dev_warn(&adc->spi->dev, - "failed to get conversion data\n"); + dev_warn(dev, "failed to get conversion data\n"); goto out; } @@ -387,43 +568,25 @@ static int mcp3911_config(struct mcp3911 *adc) u32 regval; int ret; - ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr); - - /* - * Fallback to "device-addr" due to historical mismatch between - * dt-bindings and implementation - */ - if (ret) - device_property_read_u32(dev, "device-addr", &adc->dev_addr); - if (adc->dev_addr > 3) { - dev_err(&adc->spi->dev, - "invalid device address (%i). Must be in range 0-3.\n", - adc->dev_addr); - return -EINVAL; - } - dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr); - ret = mcp3911_read(adc, MCP3911_REG_CONFIG, ®val, 2); if (ret) return ret; regval &= ~MCP3911_CONFIG_VREFEXT; if (adc->vref) { - dev_dbg(&adc->spi->dev, "use external voltage reference\n"); + dev_dbg(dev, "use external voltage reference\n"); regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 1); } else { - dev_dbg(&adc->spi->dev, - "use internal voltage reference (1.2V)\n"); + dev_dbg(dev, "use internal voltage reference (1.2V)\n"); regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 0); } regval &= ~MCP3911_CONFIG_CLKEXT; if (adc->clki) { - dev_dbg(&adc->spi->dev, "use external clock as clocksource\n"); + dev_dbg(dev, "use external clock as clocksource\n"); regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 1); } else { - dev_dbg(&adc->spi->dev, - "use crystal oscillator as clocksource\n"); + dev_dbg(dev, "use crystal oscillator as clocksource\n"); regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 0); } @@ -439,7 +602,97 @@ static int mcp3911_config(struct mcp3911 *adc) regval &= ~MCP3911_STATUSCOM_READ; regval |= FIELD_PREP(MCP3911_STATUSCOM_READ, 0x02); - return mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2); + regval &= ~MCP3911_STATUSCOM_DRHIZ; + if (device_property_read_bool(dev, "microchip,data-ready-hiz")) + regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 0); + else + regval |= FIELD_PREP(MCP3911_STATUSCOM_DRHIZ, 1); + + /* Disable offset to ignore any old values in offset register */ + regval &= ~MCP3911_STATUSCOM_EN_OFFCAL; + + ret = mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2); + if (ret) + return ret; + + /* Set gain to 1 for all channels */ + ret = mcp3911_read(adc, MCP3911_REG_GAIN, ®val, 1); + if (ret) + return ret; + + for (int i = 0; i < adc->chip->num_channels - 1; i++) { + adc->gain[i] = 1; + regval &= ~MCP3911_GAIN_MASK(i); + } + + return mcp3911_write(adc, MCP3911_REG_GAIN, regval, 1); +} + +static int mcp3910_config(struct mcp3911 *adc) +{ + struct device *dev = &adc->spi->dev; + u32 regval; + int ret; + + ret = mcp3911_read(adc, MCP3910_REG_CONFIG1, ®val, 3); + if (ret) + return ret; + + regval &= ~MCP3910_CONFIG1_VREFEXT; + if (adc->vref) { + dev_dbg(dev, "use external voltage reference\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 1); + } else { + dev_dbg(dev, "use internal voltage reference (1.2V)\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_VREFEXT, 0); + } + + regval &= ~MCP3910_CONFIG1_CLKEXT; + if (adc->clki) { + dev_dbg(dev, "use external clock as clocksource\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 1); + } else { + dev_dbg(dev, "use crystal oscillator as clocksource\n"); + regval |= FIELD_PREP(MCP3910_CONFIG1_CLKEXT, 0); + } + + ret = mcp3911_write(adc, MCP3910_REG_CONFIG1, regval, 3); + if (ret) + return ret; + + ret = mcp3911_read(adc, MCP3910_REG_STATUSCOM, ®val, 3); + if (ret) + return ret; + + /* Address counter incremented, cycle through register types */ + regval &= ~MCP3910_STATUSCOM_READ; + regval |= FIELD_PREP(MCP3910_STATUSCOM_READ, 0x02); + + regval &= ~MCP3910_STATUSCOM_DRHIZ; + if (device_property_read_bool(dev, "microchip,data-ready-hiz")) + regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 0); + else + regval |= FIELD_PREP(MCP3910_STATUSCOM_DRHIZ, 1); + + ret = mcp3911_write(adc, MCP3910_REG_STATUSCOM, regval, 3); + if (ret) + return ret; + + /* Set gain to 1 for all channels */ + ret = mcp3911_read(adc, MCP3910_REG_GAIN, ®val, 3); + if (ret) + return ret; + + for (int i = 0; i < adc->chip->num_channels - 1; i++) { + adc->gain[i] = 1; + regval &= ~MCP3911_GAIN_MASK(i); + } + ret = mcp3911_write(adc, MCP3910_REG_GAIN, regval, 3); + if (ret) + return ret; + + /* Disable offset to ignore any old values in offset register */ + return adc->chip->enable_offset(adc, 0); } static void mcp3911_cleanup_regulator(void *vref) @@ -466,26 +719,25 @@ static const struct iio_trigger_ops mcp3911_trigger_ops = { static int mcp3911_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct mcp3911 *adc; int ret; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); if (!indio_dev) return -ENOMEM; adc = iio_priv(indio_dev); adc->spi = spi; + adc->chip = spi_get_device_match_data(spi); - adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref"); + adc->vref = devm_regulator_get_optional(dev, "vref"); if (IS_ERR(adc->vref)) { if (PTR_ERR(adc->vref) == -ENODEV) { adc->vref = NULL; } else { - dev_err(&adc->spi->dev, - "failed to get regulator (%ld)\n", - PTR_ERR(adc->vref)); - return PTR_ERR(adc->vref); + return dev_err_probe(dev, PTR_ERR(adc->vref), "failed to get regulator\n"); } } else { @@ -493,34 +745,35 @@ static int mcp3911_probe(struct spi_device *spi) if (ret) return ret; - ret = devm_add_action_or_reset(&spi->dev, - mcp3911_cleanup_regulator, adc->vref); + ret = devm_add_action_or_reset(dev, mcp3911_cleanup_regulator, adc->vref); if (ret) return ret; } - adc->clki = devm_clk_get_enabled(&adc->spi->dev, NULL); + adc->clki = devm_clk_get_enabled(dev, NULL); if (IS_ERR(adc->clki)) { if (PTR_ERR(adc->clki) == -ENOENT) { adc->clki = NULL; } else { - dev_err(&adc->spi->dev, - "failed to get adc clk (%ld)\n", - PTR_ERR(adc->clki)); - return PTR_ERR(adc->clki); + return dev_err_probe(dev, PTR_ERR(adc->clki), "failed to get adc clk\n"); } } - ret = mcp3911_config(adc); + /* + * Fallback to "device-addr" due to historical mismatch between + * dt-bindings and implementation. + */ + ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr); if (ret) - return ret; + device_property_read_u32(dev, "device-addr", &adc->dev_addr); + if (adc->dev_addr > 3) { + return dev_err_probe(dev, -EINVAL, + "invalid device address (%i). Must be in range 0-3.\n", + adc->dev_addr); + } + dev_dbg(dev, "use device address %i\n", adc->dev_addr); - 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); + ret = adc->chip->config(adc); if (ret) return ret; @@ -528,12 +781,12 @@ static int mcp3911_probe(struct spi_device *spi) if (ret) return ret; - /* Set gain to 1 for all channels */ - for (int i = 0; i < MCP3911_NUM_CHANNELS; i++) { + /* Set gain to 1 for all channels */ + for (int i = 0; i < adc->chip->num_channels - 1; i++) { adc->gain[i] = 1; ret = mcp3911_update(adc, MCP3911_REG_GAIN, - MCP3911_GAIN_MASK(i), - MCP3911_GAIN_VAL(i, 0), 1); + MCP3911_GAIN_MASK(i), + MCP3911_GAIN_VAL(i, 0), 1); if (ret) return ret; } @@ -543,21 +796,20 @@ static int mcp3911_probe(struct spi_device *spi) indio_dev->info = &mcp3911_info; spi_set_drvdata(spi, indio_dev); - indio_dev->channels = mcp3911_channels; - indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels); + indio_dev->channels = adc->chip->channels; + indio_dev->num_channels = adc->chip->num_channels; 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)); + adc->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); if (!adc->trig) return -ENOMEM; adc->trig->ops = &mcp3911_trigger_ops; iio_trigger_set_drvdata(adc->trig, adc); - ret = devm_iio_trigger_register(&spi->dev, adc->trig); + ret = devm_iio_trigger_register(dev, adc->trig); if (ret) return ret; @@ -566,30 +818,120 @@ static int mcp3911_probe(struct spi_device *spi) * 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); + ret = devm_request_irq(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); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + mcp3911_trigger_handler, NULL); if (ret) return ret; - return devm_iio_device_register(&adc->spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } +static const struct mcp3911_chip_info mcp3911_chip_info[] = { + [MCP3910] = { + .channels = mcp3910_channels, + .num_channels = ARRAY_SIZE(mcp3910_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3911] = { + .channels = mcp3911_channels, + .num_channels = ARRAY_SIZE(mcp3911_channels), + .config = mcp3911_config, + .get_osr = mcp3911_get_osr, + .set_osr = mcp3911_set_osr, + .enable_offset = mcp3911_enable_offset, + .get_offset = mcp3911_get_offset, + .set_offset = mcp3911_set_offset, + .set_scale = mcp3911_set_scale, + }, + [MCP3912] = { + .channels = mcp3912_channels, + .num_channels = ARRAY_SIZE(mcp3912_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3913] = { + .channels = mcp3913_channels, + .num_channels = ARRAY_SIZE(mcp3913_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3914] = { + .channels = mcp3914_channels, + .num_channels = ARRAY_SIZE(mcp3914_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3918] = { + .channels = mcp3918_channels, + .num_channels = ARRAY_SIZE(mcp3918_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, + [MCP3919] = { + .channels = mcp3919_channels, + .num_channels = ARRAY_SIZE(mcp3919_channels), + .config = mcp3910_config, + .get_osr = mcp3910_get_osr, + .set_osr = mcp3910_set_osr, + .enable_offset = mcp3910_enable_offset, + .get_offset = mcp3910_get_offset, + .set_offset = mcp3910_set_offset, + .set_scale = mcp3910_set_scale, + }, +}; static const struct of_device_id mcp3911_dt_ids[] = { - { .compatible = "microchip,mcp3911" }, + { .compatible = "microchip,mcp3910", .data = &mcp3911_chip_info[MCP3910] }, + { .compatible = "microchip,mcp3911", .data = &mcp3911_chip_info[MCP3911] }, + { .compatible = "microchip,mcp3912", .data = &mcp3911_chip_info[MCP3912] }, + { .compatible = "microchip,mcp3913", .data = &mcp3911_chip_info[MCP3913] }, + { .compatible = "microchip,mcp3914", .data = &mcp3911_chip_info[MCP3914] }, + { .compatible = "microchip,mcp3918", .data = &mcp3911_chip_info[MCP3918] }, + { .compatible = "microchip,mcp3919", .data = &mcp3911_chip_info[MCP3919] }, { } }; MODULE_DEVICE_TABLE(of, mcp3911_dt_ids); static const struct spi_device_id mcp3911_id[] = { - { "mcp3911", 0 }, + { "mcp3910", (kernel_ulong_t)&mcp3911_chip_info[MCP3910] }, + { "mcp3911", (kernel_ulong_t)&mcp3911_chip_info[MCP3911] }, + { "mcp3912", (kernel_ulong_t)&mcp3911_chip_info[MCP3912] }, + { "mcp3913", (kernel_ulong_t)&mcp3911_chip_info[MCP3913] }, + { "mcp3914", (kernel_ulong_t)&mcp3911_chip_info[MCP3914] }, + { "mcp3918", (kernel_ulong_t)&mcp3911_chip_info[MCP3918] }, + { "mcp3919", (kernel_ulong_t)&mcp3911_chip_info[MCP3919] }, { } }; MODULE_DEVICE_TABLE(spi, mcp3911_id); diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 320e3e7e3d4d..950ff13e6dde 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1045,8 +1045,10 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) u32 regval; ret = meson_sar_adc_lock(indio_dev); - if (ret) + if (ret) { + dev_err(dev, "failed to lock adc\n"); goto err_lock; + } ret = regulator_enable(priv->vref); if (ret < 0) { @@ -1354,15 +1356,15 @@ static int meson_sar_adc_probe(struct platform_device *pdev) priv->regmap = devm_regmap_init_mmio(dev, base, priv->param->regmap_config); if (IS_ERR(priv->regmap)) - return PTR_ERR(priv->regmap); + return dev_err_probe(dev, PTR_ERR(priv->regmap), "failed to init regmap\n"); irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) - return -EINVAL; + return dev_err_probe(dev, -EINVAL, "failed to get irq\n"); ret = devm_request_irq(dev, irq, meson_sar_adc_irq, IRQF_SHARED, dev_name(dev), indio_dev); if (ret) - return ret; + return dev_err_probe(dev, ret, "failed to request irq\n"); priv->clkin = devm_clk_get(dev, "clkin"); if (IS_ERR(priv->clkin)) @@ -1384,7 +1386,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) if (!priv->adc_clk) { ret = meson_sar_adc_clk_init(indio_dev, base); if (ret) - return ret; + return dev_err_probe(dev, ret, "failed to init internal clk\n"); } priv->vref = devm_regulator_get(dev, "vref"); @@ -1426,8 +1428,10 @@ static int meson_sar_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, indio_dev); ret = iio_device_register(indio_dev); - if (ret) + if (ret) { + dev_err_probe(dev, ret, "failed to register iio device\n"); goto err_hw; + } return 0; @@ -1437,15 +1441,13 @@ err: return ret; } -static int meson_sar_adc_remove(struct platform_device *pdev) +static void meson_sar_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); iio_device_unregister(indio_dev); meson_sar_adc_hw_disable(indio_dev); - - return 0; } static int meson_sar_adc_suspend(struct device *dev) @@ -1480,7 +1482,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops, static struct platform_driver meson_sar_adc_driver = { .probe = meson_sar_adc_probe, - .remove = meson_sar_adc_remove, + .remove_new = meson_sar_adc_remove, .driver = { .name = "meson-saradc", .of_match_table = meson_sar_adc_of_match, diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 88e947f300cf..7c66c2cd5be2 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -171,7 +171,7 @@ fail_disable: return ret; } -static int mp2629_adc_remove(struct platform_device *pdev) +static void mp2629_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct mp2629_adc *info = iio_priv(indio_dev); @@ -184,8 +184,6 @@ static int mp2629_adc_remove(struct platform_device *pdev) MP2629_ADC_CONTINUOUS, 0); regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL, MP2629_ADC_START, 0); - - return 0; } static const struct of_device_id mp2629_adc_of_match[] = { @@ -200,7 +198,7 @@ static struct platform_driver mp2629_adc_driver = { .of_match_table = mp2629_adc_of_match, }, .probe = mp2629_adc_probe, - .remove = mp2629_adc_remove, + .remove_new = mp2629_adc_remove, }; module_platform_driver(mp2629_adc_driver); diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index 0e134777bdd2..3343b54e8e44 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -246,6 +246,14 @@ static int mt6577_auxadc_suspend(struct device *dev) return 0; } +static void mt6577_power_off(void *data) +{ + struct mt6577_auxadc_device *adc_dev = data; + + mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, + 0, MT6577_AUXADC_PDN_EN); +} + static int mt6577_auxadc_probe(struct platform_device *pdev) { struct mt6577_auxadc_device *adc_dev; @@ -265,29 +273,18 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels); adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(adc_dev->reg_base)) { - dev_err(&pdev->dev, "failed to get auxadc base address\n"); - return PTR_ERR(adc_dev->reg_base); - } - - adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main"); - if (IS_ERR(adc_dev->adc_clk)) { - dev_err(&pdev->dev, "failed to get auxadc clock\n"); - return PTR_ERR(adc_dev->adc_clk); - } + if (IS_ERR(adc_dev->reg_base)) + return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->reg_base), + "failed to get auxadc base address\n"); - ret = clk_prepare_enable(adc_dev->adc_clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable auxadc clock\n"); - return ret; - } + adc_dev->adc_clk = devm_clk_get_enabled(&pdev->dev, "main"); + if (IS_ERR(adc_dev->adc_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(adc_dev->adc_clk), + "failed to enable auxadc clock\n"); adc_clk_rate = clk_get_rate(adc_dev->adc_clk); - if (!adc_clk_rate) { - ret = -EINVAL; - dev_err(&pdev->dev, "null clock rate\n"); - goto err_disable_clk; - } + if (!adc_clk_rate) + return dev_err_probe(&pdev->dev, -EINVAL, "null clock rate\n"); adc_dev->dev_comp = device_get_match_data(&pdev->dev); @@ -296,36 +293,16 @@ static int mt6577_auxadc_probe(struct platform_device *pdev) mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, MT6577_AUXADC_PDN_EN, 0); mdelay(MT6577_AUXADC_POWER_READY_MS); - platform_set_drvdata(pdev, indio_dev); - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register iio device\n"); - goto err_power_off; - } - - return 0; - -err_power_off: - mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, - 0, MT6577_AUXADC_PDN_EN); -err_disable_clk: - clk_disable_unprepare(adc_dev->adc_clk); - return ret; -} - -static int mt6577_auxadc_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); + ret = devm_add_action_or_reset(&pdev->dev, mt6577_power_off, adc_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to add action to managed power off\n"); - mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC, - 0, MT6577_AUXADC_PDN_EN); - - clk_disable_unprepare(adc_dev->adc_clk); + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "failed to register iio device\n"); return 0; } @@ -352,7 +329,6 @@ static struct platform_driver mt6577_auxadc_driver = { .pm = pm_sleep_ptr(&mt6577_auxadc_pm_ops), }, .probe = mt6577_auxadc_probe, - .remove = mt6577_auxadc_remove, }; module_platform_driver(mt6577_auxadc_driver); diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index a50f39143d3e..2e60c10ee4ff 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -807,7 +807,7 @@ err_trig: return ret; } -static int mxs_lradc_adc_remove(struct platform_device *pdev) +static void mxs_lradc_adc_remove(struct platform_device *pdev) { struct iio_dev *iio = platform_get_drvdata(pdev); struct mxs_lradc_adc *adc = iio_priv(iio); @@ -816,8 +816,6 @@ static int mxs_lradc_adc_remove(struct platform_device *pdev) mxs_lradc_adc_hw_stop(adc); iio_triggered_buffer_cleanup(iio); mxs_lradc_adc_trigger_remove(iio); - - return 0; } static struct platform_driver mxs_lradc_adc_driver = { @@ -825,7 +823,7 @@ static struct platform_driver mxs_lradc_adc_driver = { .name = "mxs-lradc-adc", }, .probe = mxs_lradc_adc_probe, - .remove = mxs_lradc_adc_remove, + .remove_new = mxs_lradc_adc_remove, }; module_platform_driver(mxs_lradc_adc_driver); diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 3d9207c160eb..3a55465951e7 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -320,7 +320,7 @@ err_disable_clk: return ret; } -static int npcm_adc_remove(struct platform_device *pdev) +static void npcm_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct npcm_adc *info = iio_priv(indio_dev); @@ -333,13 +333,11 @@ static int npcm_adc_remove(struct platform_device *pdev) if (!IS_ERR(info->vref)) regulator_disable(info->vref); clk_disable_unprepare(info->adc_clk); - - return 0; } static struct platform_driver npcm_adc_driver = { .probe = npcm_adc_probe, - .remove = npcm_adc_remove, + .remove_new = npcm_adc_remove, .driver = { .name = "npcm_adc", .of_match_table = npcm_adc_match, diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index e202ea18af10..203cbbc70719 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -457,7 +457,7 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, * * The gain error include both gain error, as specified in the datasheet, and * the gain error drift. These paramenters vary depending on device and whether - * the the channel is calibrated (trimmed) or not. + * the channel is calibrated (trimmed) or not. */ static int palmas_gpadc_threshold_with_tolerance(int val, const int INL, const int gain_error, diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 64a3aeb6261c..01c5586df56d 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -957,7 +957,7 @@ out_disable_vref: return ret; } -static int pm8xxx_xoadc_remove(struct platform_device *pdev) +static void pm8xxx_xoadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct pm8xxx_xoadc *adc = iio_priv(indio_dev); @@ -965,8 +965,6 @@ static int pm8xxx_xoadc_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); regulator_disable(adc->vref); - - return 0; } static const struct xoadc_variant pm8018_variant = { @@ -1019,7 +1017,7 @@ static struct platform_driver pm8xxx_xoadc_driver = { .of_match_table = pm8xxx_xoadc_id_table, }, .probe = pm8xxx_xoadc_probe, - .remove = pm8xxx_xoadc_remove, + .remove_new = pm8xxx_xoadc_remove, }; module_platform_driver(pm8xxx_xoadc_driver); diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index b8972f673c9d..d524f2e8e927 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -559,7 +559,7 @@ err_clk_if_enable: return ret; } -static int rcar_gyroadc_remove(struct platform_device *pdev) +static void rcar_gyroadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct rcar_gyroadc *priv = iio_priv(indio_dev); @@ -573,8 +573,6 @@ static int rcar_gyroadc_remove(struct platform_device *pdev) pm_runtime_set_suspended(dev); clk_disable_unprepare(priv->clk); rcar_gyroadc_deinit_supplies(indio_dev); - - return 0; } static int rcar_gyroadc_suspend(struct device *dev) @@ -603,7 +601,7 @@ static const struct dev_pm_ops rcar_gyroadc_pm_ops = { static struct platform_driver rcar_gyroadc_driver = { .probe = rcar_gyroadc_probe, - .remove = rcar_gyroadc_remove, + .remove_new = rcar_gyroadc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = rcar_gyroadc_match, diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index ad54ef798109..71362c2ddf89 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -274,10 +274,9 @@ static int spear_adc_probe(struct platform_device *pdev) int irq; indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); - if (!indio_dev) { - dev_err(dev, "failed allocating iio device\n"); - return -ENOMEM; - } + if (!indio_dev) + return dev_err_probe(dev, -ENOMEM, + "failed allocating iio device\n"); st = iio_priv(indio_dev); @@ -297,37 +296,24 @@ static int spear_adc_probe(struct platform_device *pdev) st->adc_base_spear3xx = (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; - st->clk = devm_clk_get(dev, NULL); - if (IS_ERR(st->clk)) { - dev_err(dev, "failed getting clock\n"); - return PTR_ERR(st->clk); - } - - ret = clk_prepare_enable(st->clk); - if (ret) { - dev_err(dev, "failed enabling clock\n"); - return ret; - } + st->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(st->clk)) + return dev_err_probe(dev, PTR_ERR(st->clk), + "failed enabling clock\n"); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - goto errout2; - } + if (irq < 0) + return irq; ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, st); - if (ret < 0) { - dev_err(dev, "failed requesting interrupt\n"); - goto errout2; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed requesting interrupt\n"); if (of_property_read_u32(np, "sampling-frequency", - &st->sampling_freq)) { - dev_err(dev, "sampling-frequency missing in DT\n"); - ret = -EINVAL; - goto errout2; - } + &st->sampling_freq)) + return dev_err_probe(dev, -EINVAL, + "sampling-frequency missing in DT\n"); /* * Optional avg_samples defaults to 0, resulting in single data @@ -343,8 +329,6 @@ static int spear_adc_probe(struct platform_device *pdev) spear_adc_configure(st); - platform_set_drvdata(pdev, indio_dev); - init_completion(&st->completion); indio_dev->name = SPEAR_ADC_MOD_NAME; @@ -353,28 +337,13 @@ static int spear_adc_probe(struct platform_device *pdev) indio_dev->channels = spear_adc_iio_channels; indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) - goto errout2; + return ret; dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq); return 0; - -errout2: - clk_disable_unprepare(st->clk); - return ret; -} - -static int spear_adc_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - struct spear_adc_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - clk_disable_unprepare(st->clk); - - return 0; } #ifdef CONFIG_OF @@ -387,7 +356,6 @@ MODULE_DEVICE_TABLE(of, spear_adc_dt_ids); static struct platform_driver spear_adc_driver = { .probe = spear_adc_probe, - .remove = spear_adc_remove, .driver = { .name = SPEAR_ADC_MOD_NAME, .of_match_table = of_match_ptr(spear_adc_dt_ids), diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 2f082006550f..616dd729666a 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -17,10 +17,11 @@ #include <linux/irqdomain.h> #include <linux/mfd/syscon.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -720,8 +721,7 @@ static int stm32_adc_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, &priv->common); - priv->cfg = (const struct stm32_adc_priv_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; + priv->cfg = device_get_match_data(dev); priv->nb_adc_max = priv->cfg->num_adcs; spin_lock_init(&priv->common.lock); @@ -814,7 +814,7 @@ err_pm_stop: return ret; } -static int stm32_adc_remove(struct platform_device *pdev) +static void stm32_adc_remove(struct platform_device *pdev) { struct stm32_adc_common *common = platform_get_drvdata(pdev); struct stm32_adc_priv *priv = to_stm32_adc_priv(common); @@ -826,8 +826,6 @@ static int stm32_adc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } static int stm32_adc_core_runtime_suspend(struct device *dev) @@ -908,7 +906,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match); static struct platform_driver stm32_adc_driver = { .probe = stm32_adc_probe, - .remove = stm32_adc_remove, + .remove_new = stm32_adc_remove, .driver = { .name = "stm32-adc-core", .of_match_table = stm32_adc_of_match, diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index f7613efb870d..b5d3c9cea5c4 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2209,7 +2209,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, ret = -EINVAL; goto err; } - strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); + strscpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); ret = stm32_adc_populate_int_ch(indio_dev, name, val); if (ret == -ENOENT) continue; @@ -2513,7 +2513,7 @@ err_dma_disable: return ret; } -static int stm32_adc_remove(struct platform_device *pdev) +static void stm32_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct stm32_adc *adc = iio_priv(indio_dev); @@ -2532,8 +2532,6 @@ static int stm32_adc_remove(struct platform_device *pdev) adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } - - return 0; } static int stm32_adc_suspend(struct device *dev) @@ -2659,7 +2657,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match); static struct platform_driver stm32_adc_driver = { .probe = stm32_adc_probe, - .remove = stm32_adc_remove, + .remove_new = stm32_adc_remove, .driver = { .name = "stm32-adc", .of_match_table = stm32_adc_of_match, diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index b5cc43d12b6f..ca08ae3108b2 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1620,7 +1620,7 @@ err_cleanup: return ret; } -static int stm32_dfsdm_adc_remove(struct platform_device *pdev) +static void stm32_dfsdm_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -1629,8 +1629,6 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) of_platform_depopulate(&pdev->dev); iio_device_unregister(indio_dev); stm32_dfsdm_dma_release(indio_dev); - - return 0; } static int stm32_dfsdm_adc_suspend(struct device *dev) @@ -1677,7 +1675,7 @@ static struct platform_driver stm32_dfsdm_adc_driver = { .pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops), }, .probe = stm32_dfsdm_adc_probe, - .remove = stm32_dfsdm_adc_remove, + .remove_new = stm32_dfsdm_adc_remove, }; module_platform_driver(stm32_dfsdm_adc_driver); diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index 0f6ebb3061a0..a05d978b8cb8 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -436,7 +436,7 @@ pm_put: return ret; } -static int stm32_dfsdm_core_remove(struct platform_device *pdev) +static void stm32_dfsdm_core_remove(struct platform_device *pdev) { struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev); @@ -446,8 +446,6 @@ static int stm32_dfsdm_core_remove(struct platform_device *pdev) pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); stm32_dfsdm_clk_disable_unprepare(dfsdm); - - return 0; } static int stm32_dfsdm_core_suspend(struct device *dev) @@ -508,7 +506,7 @@ static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { static struct platform_driver stm32_dfsdm_driver = { .probe = stm32_dfsdm_probe, - .remove = stm32_dfsdm_core_remove, + .remove_new = stm32_dfsdm_core_remove, .driver = { .name = "stm32-dfsdm", .of_match_table = stm32_dfsdm_of_match, diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 25bba96367a8..100ecced5fc1 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -669,7 +669,7 @@ err_map: return ret; } -static int sun4i_gpadc_remove(struct platform_device *pdev) +static void sun4i_gpadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct sun4i_gpadc_iio *info = iio_priv(indio_dev); @@ -678,12 +678,10 @@ static int sun4i_gpadc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); if (!IS_ENABLED(CONFIG_THERMAL_OF)) - return 0; + return; if (!info->no_irq) iio_map_array_unregister(indio_dev); - - return 0; } static const struct platform_device_id sun4i_gpadc_id[] = { @@ -702,7 +700,7 @@ static struct platform_driver sun4i_gpadc_driver = { }, .id_table = sun4i_gpadc_id, .probe = sun4i_gpadc_probe, - .remove = sun4i_gpadc_remove, + .remove_new = sun4i_gpadc_remove, }; MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_id); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 50c450e7a55f..6c2cb3dabbbf 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -154,7 +154,6 @@ static void adc081c_reg_disable(void *reg) static int adc081c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct iio_dev *iio; struct adc081c *adc; const struct adcxx1c_model *model; @@ -163,10 +162,7 @@ static int adc081c_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; - if (dev_fwnode(&client->dev)) - model = device_get_match_data(&client->dev); - else - model = &adcxx1c_models[id->driver_data]; + model = i2c_get_match_data(client); iio = devm_iio_device_alloc(&client->dev, sizeof(*adc)); if (!iio) @@ -207,9 +203,9 @@ static int adc081c_probe(struct i2c_client *client) } static const struct i2c_device_id adc081c_id[] = { - { "adc081c", ADC081C }, - { "adc101c", ADC101C }, - { "adc121c", ADC121C }, + { "adc081c", (kernel_ulong_t)&adcxx1c_models[ADC081C] }, + { "adc101c", (kernel_ulong_t)&adcxx1c_models[ADC101C] }, + { "adc121c", (kernel_ulong_t)&adcxx1c_models[ADC121C] }, { } }; MODULE_DEVICE_TABLE(i2c, adc081c_id); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 075c75a87544..6799ea49dbc7 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -976,16 +976,13 @@ static int ads1015_set_conv_mode(struct ads1015_data *data, int mode) static int ads1015_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct ads1015_chip_data *chip; struct iio_dev *indio_dev; struct ads1015_data *data; int ret; int i; - chip = device_get_match_data(&client->dev); - if (!chip) - chip = (const struct ads1015_chip_data *)id->driver_data; + chip = i2c_get_match_data(client); if (!chip) return dev_err_probe(&client->dev, -EINVAL, "Unknown chip\n"); @@ -1047,11 +1044,13 @@ static int ads1015_probe(struct i2c_client *client) 1 << ADS1015_CFG_COMP_LAT_SHIFT; switch (irq_trig) { + case IRQF_TRIGGER_FALLING: case IRQF_TRIGGER_LOW: cfg_comp |= ADS1015_CFG_COMP_POL_LOW << ADS1015_CFG_COMP_POL_SHIFT; break; case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: cfg_comp |= ADS1015_CFG_COMP_POL_HIGH << ADS1015_CFG_COMP_POL_SHIFT; break; diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 8db7a01cb5fb..c755e8cd5220 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -681,7 +681,7 @@ err_dma: return err; } -static int tiadc_remove(struct platform_device *pdev) +static void tiadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct tiadc_device *adc_dev = iio_priv(indio_dev); @@ -697,8 +697,6 @@ static int tiadc_remove(struct platform_device *pdev) step_en = get_adc_step_mask(adc_dev); am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en); - - return 0; } static int tiadc_suspend(struct device *dev) @@ -747,7 +745,7 @@ static struct platform_driver tiadc_driver = { .of_match_table = ti_adc_dt_ids, }, .probe = tiadc_probe, - .remove = tiadc_remove, + .remove_new = tiadc_remove, }; module_platform_driver(tiadc_driver); diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index c279c4f2c9b7..4a247ca25a44 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -892,7 +892,7 @@ err_current_generator: return ret; } -static int twl4030_madc_remove(struct platform_device *pdev) +static void twl4030_madc_remove(struct platform_device *pdev) { struct iio_dev *iio_dev = platform_get_drvdata(pdev); struct twl4030_madc_data *madc = iio_priv(iio_dev); @@ -903,8 +903,6 @@ static int twl4030_madc_remove(struct platform_device *pdev) twl4030_madc_set_power(madc, 0); regulator_disable(madc->usb3v1); - - return 0; } #ifdef CONFIG_OF @@ -917,7 +915,7 @@ MODULE_DEVICE_TABLE(of, twl_madc_of_match); static struct platform_driver twl4030_madc_driver = { .probe = twl4030_madc_probe, - .remove = twl4030_madc_remove, + .remove_new = twl4030_madc_remove, .driver = { .name = "twl4030_madc", .of_match_table = of_match_ptr(twl_madc_of_match), diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 32873fb5f367..78bf55438b2c 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -16,9 +16,10 @@ */ #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/of_platform.h> +#include <linux/property.h> #include <linux/mfd/twl.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -879,17 +880,14 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct twl6030_gpadc_data *gpadc; const struct twl6030_gpadc_platform_data *pdata; - const struct of_device_id *match; struct iio_dev *indio_dev; int irq; int ret; - match = of_match_device(of_twl6030_match_tbl, dev); - if (!match) + pdata = device_get_match_data(&pdev->dev); + if (!pdata) return -EINVAL; - pdata = match->data; - indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); if (!indio_dev) return -ENOMEM; @@ -968,14 +966,12 @@ static int twl6030_gpadc_probe(struct platform_device *pdev) return iio_device_register(indio_dev); } -static int twl6030_gpadc_remove(struct platform_device *pdev) +static void twl6030_gpadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); iio_device_unregister(indio_dev); - - return 0; } static int twl6030_gpadc_suspend(struct device *pdev) @@ -1007,7 +1003,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, static struct platform_driver twl6030_gpadc_driver = { .probe = twl6030_gpadc_probe, - .remove = twl6030_gpadc_remove, + .remove_new = twl6030_gpadc_remove, .driver = { .name = DRIVER_NAME, .pm = pm_sleep_ptr(&twl6030_gpadc_pm_ops), diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index ae31aafd2653..e4548df3f8fb 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -916,7 +916,7 @@ error_adc_clk_enable: return ret; } -static int vf610_adc_remove(struct platform_device *pdev) +static void vf610_adc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct vf610_adc *info = iio_priv(indio_dev); @@ -925,8 +925,6 @@ static int vf610_adc_remove(struct platform_device *pdev) iio_triggered_buffer_cleanup(indio_dev); regulator_disable(info->vref); clk_disable_unprepare(info->clk); - - return 0; } static int vf610_adc_suspend(struct device *dev) @@ -974,7 +972,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, static struct platform_driver vf610_adc_driver = { .probe = vf610_adc_probe, - .remove = vf610_adc_remove, + .remove_new = vf610_adc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = vf610_adc_match, diff --git a/drivers/iio/addac/Kconfig b/drivers/iio/addac/Kconfig index 397544f23b85..16876b8b5c4e 100644 --- a/drivers/iio/addac/Kconfig +++ b/drivers/iio/addac/Kconfig @@ -40,6 +40,7 @@ config STX104 select REGMAP_MMIO select GPIOLIB select GPIO_REGMAP + select I8254 help Say yes here to build support for the Apex Embedded Systems STX104 integrated analog PC/104 card. diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index 6b0e8218f150..7af3e4b8fe3b 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -442,11 +442,29 @@ static int ad74413r_set_channel_function(struct ad74413r_state *st, int ret; ret = regmap_update_bits(st->regmap, + AD74413R_REG_CH_FUNC_SETUP_X(channel), + AD74413R_CH_FUNC_SETUP_MASK, + CH_FUNC_HIGH_IMPEDANCE); + if (ret) + return ret; + + /* Set DAC code to 0 prior to changing channel function */ + ret = ad74413r_set_channel_dac_code(st, channel, 0); + if (ret) + return ret; + + /* Delay required before transition to new desired mode */ + usleep_range(130, 150); + + ret = regmap_update_bits(st->regmap, AD74413R_REG_CH_FUNC_SETUP_X(channel), AD74413R_CH_FUNC_SETUP_MASK, func); if (ret) return ret; + /* Delay required before updating the new DAC code */ + usleep_range(150, 170); + if (func == CH_FUNC_CURRENT_INPUT_LOOP_POWER) ret = regmap_set_bits(st->regmap, AD74413R_REG_ADC_CONFIG_X(channel), @@ -705,8 +723,8 @@ static int ad74413r_get_input_current_scale(struct ad74413r_state *st, return IIO_VAL_FRACTIONAL; } -static int ad74413_get_input_current_offset(struct ad74413r_state *st, - unsigned int channel, int *val) +static int ad74413r_get_input_current_offset(struct ad74413r_state *st, + unsigned int channel, int *val) { unsigned int range; int voltage_range; @@ -991,7 +1009,7 @@ static int ad74413r_read_raw(struct iio_dev *indio_dev, return ad74413r_get_input_voltage_offset(st, chan->channel, val); case IIO_CURRENT: - return ad74413_get_input_current_offset(st, + return ad74413r_get_input_current_offset(st, chan->channel, val); default: return -EINVAL; diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c index d1f7ce033b46..6946a65512ca 100644 --- a/drivers/iio/addac/stx104.c +++ b/drivers/iio/addac/stx104.c @@ -8,6 +8,7 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/gpio/regmap.h> +#include <linux/i8254.h> #include <linux/iio/iio.h> #include <linux/iio/types.h> #include <linux/isa.h> @@ -55,6 +56,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses"); #define STX104_ADC_STATUS (STX104_AIO_BASE + 0x8) #define STX104_ADC_CONTROL (STX104_AIO_BASE + 0x9) #define STX104_ADC_CONFIGURATION (STX104_AIO_BASE + 0x11) +#define STX104_I8254_BASE (STX104_AIO_BASE + 0x12) #define STX104_AIO_DATA_STRIDE 2 #define STX104_DAC_OFFSET(_channel) (STX104_DAC_BASE + STX104_AIO_DATA_STRIDE * (_channel)) @@ -77,6 +79,7 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses"); /* ADC Configuration */ #define STX104_GAIN GENMASK(1, 0) #define STX104_ADBU BIT(2) +#define STX104_RBK GENMASK(7, 4) #define STX104_BIPOLAR 0 #define STX104_GAIN_X1 0 #define STX104_GAIN_X2 1 @@ -168,6 +171,32 @@ static const struct regmap_config dio_regmap_config = { .io_port = true, }; +static const struct regmap_range pit_wr_ranges[] = { + regmap_reg_range(0x0, 0x3), +}; +static const struct regmap_range pit_rd_ranges[] = { + regmap_reg_range(0x0, 0x2), +}; +static const struct regmap_access_table pit_wr_table = { + .yes_ranges = pit_wr_ranges, + .n_yes_ranges = ARRAY_SIZE(pit_wr_ranges), +}; +static const struct regmap_access_table pit_rd_table = { + .yes_ranges = pit_rd_ranges, + .n_yes_ranges = ARRAY_SIZE(pit_rd_ranges), +}; + +static const struct regmap_config pit_regmap_config = { + .name = "i8254", + .reg_bits = 8, + .reg_stride = 1, + .reg_base = STX104_I8254_BASE, + .val_bits = 8, + .io_port = true, + .wr_table = &pit_wr_table, + .rd_table = &pit_rd_table, +}; + static int stx104_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -339,6 +368,21 @@ static const char *stx104_names[STX104_NGPIO] = { "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3" }; +static int bank_select_i8254(struct regmap *map) +{ + const u8 select_i8254[] = { 0x3, 0xB, 0xA }; + size_t i; + int err; + + for (i = 0; i < ARRAY_SIZE(select_i8254); i++) { + err = regmap_write_bits(map, STX104_ADC_CONFIGURATION, STX104_RBK, select_i8254[i]); + if (err) + return err; + } + + return 0; +} + static int stx104_init_hw(struct stx104_iio *const priv) { int err; @@ -361,7 +405,7 @@ static int stx104_init_hw(struct stx104_iio *const priv) if (err) return err; - return 0; + return bank_select_i8254(priv->aio_ctl_map); } static int stx104_probe(struct device *dev, unsigned int id) @@ -369,6 +413,7 @@ static int stx104_probe(struct device *dev, unsigned int id) struct iio_dev *indio_dev; struct stx104_iio *priv; struct gpio_regmap_config gpio_config; + struct i8254_regmap_config pit_config; void __iomem *stx104_base; struct regmap *aio_ctl_map; struct regmap *aio_data_map; @@ -406,6 +451,11 @@ static int stx104_probe(struct device *dev, unsigned int id) return dev_err_probe(dev, PTR_ERR(dio_map), "Unable to initialize dio register map\n"); + pit_config.map = devm_regmap_init_mmio(dev, stx104_base, &pit_regmap_config); + if (IS_ERR(pit_config.map)) + return dev_err_probe(dev, PTR_ERR(pit_config.map), + "Unable to initialize i8254 register map\n"); + priv = iio_priv(indio_dev); priv->aio_ctl_map = aio_ctl_map; priv->aio_data_map = aio_data_map; @@ -449,7 +499,13 @@ static int stx104_probe(struct device *dev, unsigned int id) .drvdata = dio_map, }; - return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); + err = PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); + if (err) + return err; + + pit_config.parent = dev; + + return devm_i8254_regmap_register(dev, &pit_config); } static struct isa_driver stx104_driver = { @@ -464,3 +520,4 @@ module_isa_driver(stx104_driver, num_stx104); MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(I8254); diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c index 108f0f1685ef..e87d35d50a95 100644 --- a/drivers/iio/amplifiers/hmc425a.c +++ b/drivers/iio/amplifiers/hmc425a.c @@ -21,6 +21,7 @@ enum hmc425a_type { ID_HMC425A, + ID_HMC540S, }; struct hmc425a_chip_info { @@ -70,6 +71,9 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev, case ID_HMC425A: gain = ~code * -500; break; + case ID_HMC540S: + gain = ~code * -1000; + break; } *val = gain / 1000; @@ -106,6 +110,9 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev, case ID_HMC425A: code = ~((abs(gain) / 500) & 0x3F); break; + case ID_HMC540S: + code = ~((abs(gain) / 1000) & 0xF); + break; } mutex_lock(&st->lock); @@ -157,6 +164,7 @@ static const struct iio_chan_spec hmc425a_channels[] = { /* Match table for of_platform binding */ static const struct of_device_id hmc425a_of_match[] = { { .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A }, + { .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S }, {}, }; MODULE_DEVICE_TABLE(of, hmc425a_of_match); @@ -171,6 +179,15 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = { .gain_max = 0, .default_gain = -0x40, /* set default gain -31.5db*/ }, + [ID_HMC540S] = { + .name = "hmc540s", + .channels = hmc425a_channels, + .num_channels = ARRAY_SIZE(hmc425a_channels), + .num_gpios = 4, + .gain_min = -15000, + .gain_max = 0, + .default_gain = -0x10, /* set default gain -15.0db*/ + }, }; static int hmc425a_probe(struct platform_device *pdev) diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index 8fc926a2d33b..761a853a4d17 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -203,7 +203,6 @@ MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids); static int atlas_ezo_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct atlas_ezo_device *chip; struct atlas_ezo_data *data; struct iio_dev *indio_dev; @@ -212,10 +211,7 @@ static int atlas_ezo_probe(struct i2c_client *client) if (!indio_dev) return -ENOMEM; - if (dev_fwnode(&client->dev)) - chip = device_get_match_data(&client->dev); - else - chip = (const struct atlas_ezo_device *)id->driver_data; + chip = i2c_get_match_data(client); if (!chip) return -EINVAL; diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index fb15bb216019..baf93e5e3ca7 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -87,7 +87,7 @@ enum { struct atlas_data { struct i2c_client *client; struct iio_trigger *trig; - struct atlas_device *chip; + const struct atlas_device *chip; struct regmap *regmap; struct irq_work work; unsigned int interrupt_enabled; @@ -353,7 +353,7 @@ struct atlas_device { int delay; }; -static struct atlas_device atlas_devices[] = { +static const struct atlas_device atlas_devices[] = { [ATLAS_PH_SM] = { .channels = atlas_ph_channels, .num_channels = 3, @@ -589,30 +589,29 @@ static const struct iio_info atlas_info = { }; static const struct i2c_device_id atlas_id[] = { - { "atlas-ph-sm", ATLAS_PH_SM }, - { "atlas-ec-sm", ATLAS_EC_SM }, - { "atlas-orp-sm", ATLAS_ORP_SM }, - { "atlas-do-sm", ATLAS_DO_SM }, - { "atlas-rtd-sm", ATLAS_RTD_SM }, + { "atlas-ph-sm", (kernel_ulong_t)&atlas_devices[ATLAS_PH_SM] }, + { "atlas-ec-sm", (kernel_ulong_t)&atlas_devices[ATLAS_EC_SM] }, + { "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] }, + { "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] }, + { "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] }, {} }; MODULE_DEVICE_TABLE(i2c, atlas_id); static const struct of_device_id atlas_dt_ids[] = { - { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, }, - { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, }, - { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, }, - { .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, }, - { .compatible = "atlas,rtd-sm", .data = (void *)ATLAS_RTD_SM, }, + { .compatible = "atlas,ph-sm", .data = &atlas_devices[ATLAS_PH_SM] }, + { .compatible = "atlas,ec-sm", .data = &atlas_devices[ATLAS_EC_SM] }, + { .compatible = "atlas,orp-sm", .data = &atlas_devices[ATLAS_ORP_SM] }, + { .compatible = "atlas,do-sm", .data = &atlas_devices[ATLAS_DO_SM] }, + { .compatible = "atlas,rtd-sm", .data = &atlas_devices[ATLAS_RTD_SM] }, { } }; MODULE_DEVICE_TABLE(of, atlas_dt_ids); static int atlas_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct atlas_data *data; - struct atlas_device *chip; + const struct atlas_device *chip; struct iio_trigger *trig; struct iio_dev *indio_dev; int ret; @@ -621,10 +620,7 @@ static int atlas_probe(struct i2c_client *client) if (!indio_dev) return -ENOMEM; - if (!dev_fwnode(&client->dev)) - chip = &atlas_devices[id->driver_data]; - else - chip = &atlas_devices[(unsigned long)device_get_match_data(&client->dev)]; + chip = i2c_get_match_data(client); indio_dev->info = &atlas_info; indio_dev->name = ATLAS_DRV_NAME; diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index b509cff9ce37..21730d62b5c8 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -114,6 +114,7 @@ struct sgp_data { }; struct sgp_device { + unsigned long product_id; const struct iio_chan_spec *channels; int num_channels; }; @@ -182,10 +183,12 @@ static const struct iio_chan_spec sgpc3_channels[] = { static const struct sgp_device sgp_devices[] = { [SGP30] = { + .product_id = SGP30, .channels = sgp30_channels, .num_channels = ARRAY_SIZE(sgp30_channels), }, [SGPC3] = { + .product_id = SGPC3, .channels = sgpc3_channels, .num_channels = ARRAY_SIZE(sgpc3_channels), }, @@ -491,28 +494,25 @@ static const struct iio_info sgp_info = { }; static const struct of_device_id sgp_dt_ids[] = { - { .compatible = "sensirion,sgp30", .data = (void *)SGP30 }, - { .compatible = "sensirion,sgpc3", .data = (void *)SGPC3 }, + { .compatible = "sensirion,sgp30", .data = &sgp_devices[SGP30] }, + { .compatible = "sensirion,sgpc3", .data = &sgp_devices[SGPC3] }, { } }; static int sgp_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); + const struct sgp_device *match_data; struct device *dev = &client->dev; struct iio_dev *indio_dev; struct sgp_data *data; - unsigned long product_id; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; - if (dev_fwnode(dev)) - product_id = (unsigned long)device_get_match_data(dev); - else - product_id = id->driver_data; + match_data = i2c_get_match_data(client); data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); @@ -528,15 +528,15 @@ static int sgp_probe(struct i2c_client *client) data->feature_set = be16_to_cpu(data->buffer.raw_words[0].value); - ret = sgp_check_compat(data, product_id); + ret = sgp_check_compat(data, match_data->product_id); if (ret) return ret; indio_dev->info = &sgp_info; indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = sgp_devices[product_id].channels; - indio_dev->num_channels = sgp_devices[product_id].num_channels; + indio_dev->channels = match_data->channels; + indio_dev->num_channels = match_data->num_channels; sgp_init(data); @@ -562,8 +562,8 @@ static void sgp_remove(struct i2c_client *client) } static const struct i2c_device_id sgp_id[] = { - { "sgp30", SGP30 }, - { "sgpc3", SGPC3 }, + { "sgp30", (kernel_ulong_t)&sgp_devices[SGP30] }, + { "sgpc3", (kernel_ulong_t)&sgp_devices[SGPC3] }, { } }; diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 13555f4f401a..5b358bcd311b 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -342,19 +342,17 @@ static const struct vz89x_chip_data vz89x_chips[] = { }; static const struct of_device_id vz89x_dt_ids[] = { - { .compatible = "sgx,vz89x", .data = (void *) VZ89X }, - { .compatible = "sgx,vz89te", .data = (void *) VZ89TE }, + { .compatible = "sgx,vz89x", .data = &vz89x_chips[VZ89X] }, + { .compatible = "sgx,vz89te", .data = &vz89x_chips[VZ89TE] }, { } }; MODULE_DEVICE_TABLE(of, vz89x_dt_ids); static int vz89x_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct iio_dev *indio_dev; struct vz89x_data *data; - int chip_id; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -369,14 +367,10 @@ static int vz89x_probe(struct i2c_client *client) else return -EOPNOTSUPP; - if (!dev_fwnode(dev)) - chip_id = id->driver_data; - else - chip_id = (unsigned long)device_get_match_data(dev); + data->chip = i2c_get_match_data(client); i2c_set_clientdata(client, indio_dev); data->client = client; - data->chip = &vz89x_chips[chip_id]; data->last_update = jiffies - HZ; mutex_init(&data->lock); @@ -391,8 +385,8 @@ static int vz89x_probe(struct i2c_client *client) } static const struct i2c_device_id vz89x_id[] = { - { "vz89x", VZ89X }, - { "vz89te", VZ89TE }, + { "vz89x", (kernel_ulong_t)&vz89x_chips[VZ89X] }, + { "vz89te", (kernel_ulong_t)&vz89x_chips[VZ89TE] }, { } }; MODULE_DEVICE_TABLE(i2c, vz89x_id); diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c index 83ce9489259c..7332064d0852 100644 --- a/drivers/iio/dac/dpot-dac.c +++ b/drivers/iio/dac/dpot-dac.c @@ -226,15 +226,13 @@ disable_reg: return ret; } -static int dpot_dac_remove(struct platform_device *pdev) +static void dpot_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct dpot_dac *dac = iio_priv(indio_dev); iio_device_unregister(indio_dev); regulator_disable(dac->vref); - - return 0; } static const struct of_device_id dpot_dac_match[] = { @@ -245,7 +243,7 @@ MODULE_DEVICE_TABLE(of, dpot_dac_match); static struct platform_driver dpot_dac_driver = { .probe = dpot_dac_probe, - .remove = dpot_dac_remove, + .remove_new = dpot_dac_remove, .driver = { .name = "iio-dpot-dac", .of_match_table = dpot_dac_match, diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index 60467c6f2c6e..b3aa4443a6a4 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -165,7 +165,7 @@ dis_reg: return ret; } -static int lpc18xx_dac_remove(struct platform_device *pdev) +static void lpc18xx_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct lpc18xx_dac *dac = iio_priv(indio_dev); @@ -175,8 +175,6 @@ static int lpc18xx_dac_remove(struct platform_device *pdev) writel(0, dac->base + LPC18XX_DAC_CTRL); clk_disable_unprepare(dac->clk); regulator_disable(dac->vref); - - return 0; } static const struct of_device_id lpc18xx_dac_match[] = { @@ -187,7 +185,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_dac_match); static struct platform_driver lpc18xx_dac_driver = { .probe = lpc18xx_dac_probe, - .remove = lpc18xx_dac_remove, + .remove_new = lpc18xx_dac_remove, .driver = { .name = "lpc18xx-dac", .of_match_table = lpc18xx_dac_match, diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index f4a3124d29f2..25bb1c0490af 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -30,9 +30,14 @@ #define MCP472X_REF_VREF_UNBUFFERED 0x02 #define MCP472X_REF_VREF_BUFFERED 0x03 +struct mcp4725_chip_info { + const struct iio_chan_spec *chan_spec; + u8 dac_reg_offset; + bool use_ext_ref_voltage; +}; + struct mcp4725_data { struct i2c_client *client; - int id; unsigned ref_mode; bool vref_buffered; u16 dac_value; @@ -384,6 +389,7 @@ static int mcp4725_probe_dt(struct device *dev, static int mcp4725_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); + const struct mcp4725_chip_info *info; struct mcp4725_data *data; struct iio_dev *indio_dev; struct mcp4725_platform_data *pdata, pdata_dt; @@ -398,10 +404,7 @@ static int mcp4725_probe(struct i2c_client *client) data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - if (dev_fwnode(&client->dev)) - data->id = (uintptr_t)device_get_match_data(&client->dev); - else - data->id = id->driver_data; + info = i2c_get_match_data(client); pdata = dev_get_platdata(&client->dev); if (!pdata) { @@ -414,7 +417,7 @@ static int mcp4725_probe(struct i2c_client *client) pdata = &pdata_dt; } - if (data->id == MCP4725 && pdata->use_vref) { + if (info->use_ext_ref_voltage && pdata->use_vref) { dev_err(&client->dev, "external reference is unavailable on MCP4725"); return -EINVAL; @@ -455,12 +458,12 @@ static int mcp4725_probe(struct i2c_client *client) indio_dev->name = id->name; indio_dev->info = &mcp4725_info; - indio_dev->channels = &mcp472x_channel[id->driver_data]; + indio_dev->channels = info->chan_spec; indio_dev->num_channels = 1; indio_dev->modes = INDIO_DIRECT_MODE; /* read current DAC value and settings */ - err = i2c_master_recv(client, inbuf, data->id == MCP4725 ? 3 : 4); + err = i2c_master_recv(client, inbuf, info->dac_reg_offset); if (err < 0) { dev_err(&client->dev, "failed to read DAC value"); @@ -470,10 +473,10 @@ static int mcp4725_probe(struct i2c_client *client) data->powerdown = pd > 0; data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); - if (data->id == MCP4726) + if (!info->use_ext_ref_voltage) ref = (inbuf[3] >> 3) & 0x3; - if (data->id == MCP4726 && ref != data->ref_mode) { + if (!info->use_ext_ref_voltage && ref != data->ref_mode) { dev_info(&client->dev, "voltage reference mode differs (conf: %u, eeprom: %u), setting %u", data->ref_mode, ref, data->ref_mode); @@ -510,9 +513,20 @@ static void mcp4725_remove(struct i2c_client *client) regulator_disable(data->vdd_reg); } +static const struct mcp4725_chip_info mcp4725 = { + .chan_spec = &mcp472x_channel[MCP4725], + .dac_reg_offset = 3, + .use_ext_ref_voltage = true, +}; + +static const struct mcp4725_chip_info mcp4726 = { + .chan_spec = &mcp472x_channel[MCP4726], + .dac_reg_offset = 4, +}; + static const struct i2c_device_id mcp4725_id[] = { - { "mcp4725", MCP4725 }, - { "mcp4726", MCP4726 }, + { "mcp4725", (kernel_ulong_t)&mcp4725 }, + { "mcp4726", (kernel_ulong_t)&mcp4726 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp4725_id); @@ -520,11 +534,11 @@ MODULE_DEVICE_TABLE(i2c, mcp4725_id); static const struct of_device_id mcp4725_of_match[] = { { .compatible = "microchip,mcp4725", - .data = (void *)MCP4725 + .data = &mcp4725 }, { .compatible = "microchip,mcp4726", - .data = (void *)MCP4726 + .data = &mcp4726 }, { } }; diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 83bf184e3adc..e150ac729154 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -9,9 +9,12 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of_platform.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/reset.h> @@ -94,16 +97,12 @@ static int stm32_dac_probe(struct platform_device *pdev) struct reset_control *rst; int ret; - if (!dev->of_node) - return -ENODEV; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; platform_set_drvdata(pdev, &priv->common); - cfg = (const struct stm32_dac_cfg *) - of_match_device(dev->driver->of_match_table, dev)->data; + cfg = device_get_match_data(dev); mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mmio)) @@ -183,7 +182,7 @@ err_pm_stop: return ret; } -static int stm32_dac_remove(struct platform_device *pdev) +static void stm32_dac_remove(struct platform_device *pdev) { pm_runtime_get_sync(&pdev->dev); of_platform_depopulate(&pdev->dev); @@ -191,8 +190,6 @@ static int stm32_dac_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } static int stm32_dac_core_resume(struct device *dev) @@ -249,7 +246,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); static struct platform_driver stm32_dac_driver = { .probe = stm32_dac_probe, - .remove = stm32_dac_remove, + .remove_new = stm32_dac_remove, .driver = { .name = "stm32-dac-core", .of_match_table = stm32_dac_of_match, diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 15eb44075107..5a722f307e7e 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -11,12 +11,13 @@ #include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/kernel.h> +#include <linux/kstrtox.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/string_helpers.h> +#include <linux/string_choices.h> #include "stm32-dac-core.h" @@ -361,7 +362,7 @@ err_pm_put: return ret; } -static int stm32_dac_remove(struct platform_device *pdev) +static void stm32_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -370,8 +371,6 @@ static int stm32_dac_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } static int stm32_dac_suspend(struct device *dev) @@ -399,7 +398,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); static struct platform_driver stm32_dac_driver = { .probe = stm32_dac_probe, - .remove = stm32_dac_remove, + .remove_new = stm32_dac_remove, .driver = { .name = "stm32-dac", .of_match_table = stm32_dac_of_match, diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index bab11b9adc25..efb1269a77c1 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -313,7 +313,6 @@ static int dac5571_probe(struct i2c_client *client) const struct dac5571_spec *spec; struct dac5571_data *data; struct iio_dev *indio_dev; - enum chip_id chip_id; int ret, i; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); @@ -329,12 +328,7 @@ static int dac5571_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = dac5571_channels; - if (dev_fwnode(dev)) - chip_id = (uintptr_t)device_get_match_data(dev); - else - chip_id = id->driver_data; - - spec = &dac5571_spec[chip_id]; + spec = i2c_get_match_data(client); indio_dev->num_channels = spec->num_channels; data->spec = spec; @@ -392,31 +386,31 @@ static void dac5571_remove(struct i2c_client *i2c) } static const struct of_device_id dac5571_of_id[] = { - {.compatible = "ti,dac5571", .data = (void *)single_8bit}, - {.compatible = "ti,dac6571", .data = (void *)single_10bit}, - {.compatible = "ti,dac7571", .data = (void *)single_12bit}, - {.compatible = "ti,dac5574", .data = (void *)quad_8bit}, - {.compatible = "ti,dac6574", .data = (void *)quad_10bit}, - {.compatible = "ti,dac7574", .data = (void *)quad_12bit}, - {.compatible = "ti,dac5573", .data = (void *)quad_8bit}, - {.compatible = "ti,dac6573", .data = (void *)quad_10bit}, - {.compatible = "ti,dac7573", .data = (void *)quad_12bit}, - {.compatible = "ti,dac121c081", .data = (void *)single_12bit}, + {.compatible = "ti,dac121c081", .data = &dac5571_spec[single_12bit] }, + {.compatible = "ti,dac5571", .data = &dac5571_spec[single_8bit] }, + {.compatible = "ti,dac6571", .data = &dac5571_spec[single_10bit] }, + {.compatible = "ti,dac7571", .data = &dac5571_spec[single_12bit] }, + {.compatible = "ti,dac5574", .data = &dac5571_spec[quad_8bit] }, + {.compatible = "ti,dac6574", .data = &dac5571_spec[quad_10bit] }, + {.compatible = "ti,dac7574", .data = &dac5571_spec[quad_12bit] }, + {.compatible = "ti,dac5573", .data = &dac5571_spec[quad_8bit] }, + {.compatible = "ti,dac6573", .data = &dac5571_spec[quad_10bit] }, + {.compatible = "ti,dac7573", .data = &dac5571_spec[quad_12bit] }, {} }; MODULE_DEVICE_TABLE(of, dac5571_of_id); static const struct i2c_device_id dac5571_id[] = { - {"dac5571", single_8bit}, - {"dac6571", single_10bit}, - {"dac7571", single_12bit}, - {"dac5574", quad_8bit}, - {"dac6574", quad_10bit}, - {"dac7574", quad_12bit}, - {"dac5573", quad_8bit}, - {"dac6573", quad_10bit}, - {"dac7573", quad_12bit}, - {"dac121c081", single_12bit}, + {"dac121c081", (kernel_ulong_t)&dac5571_spec[single_12bit] }, + {"dac5571", (kernel_ulong_t)&dac5571_spec[single_8bit] }, + {"dac6571", (kernel_ulong_t)&dac5571_spec[single_10bit] }, + {"dac7571", (kernel_ulong_t)&dac5571_spec[single_12bit] }, + {"dac5574", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + {"dac6574", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + {"dac7574", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, + {"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] }, + {"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] }, + {"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] }, {} }; MODULE_DEVICE_TABLE(i2c, dac5571_id); diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index fc182250c622..de73bc5a1c93 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -231,7 +231,7 @@ error_iio_device_register: return ret; } -static int vf610_dac_remove(struct platform_device *pdev) +static void vf610_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct vf610_dac *info = iio_priv(indio_dev); @@ -239,8 +239,6 @@ static int vf610_dac_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); vf610_dac_exit(info); clk_disable_unprepare(info->clk); - - return 0; } static int vf610_dac_suspend(struct device *dev) @@ -274,7 +272,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend, static struct platform_driver vf610_dac_driver = { .probe = vf610_dac_probe, - .remove = vf610_dac_remove, + .remove_new = vf610_dac_remove, .driver = { .name = "vf610-dac", .of_match_table = vf610_dac_match, diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 85e289700c3c..4abf80f75ef5 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -33,7 +33,6 @@ enum { struct adf4350_state { struct spi_device *spi; - struct regulator *reg; struct gpio_desc *lock_detect_gpiod; struct adf4350_platform_data *pdata; struct clk *clk; @@ -469,6 +468,15 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) return pdata; } +static void adf4350_power_down(void *data) +{ + struct iio_dev *indio_dev = data; + struct adf4350_state *st = iio_priv(indio_dev); + + st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; + adf4350_sync_config(st); +} + static int adf4350_probe(struct spi_device *spi) { struct adf4350_platform_data *pdata; @@ -491,31 +499,21 @@ static int adf4350_probe(struct spi_device *spi) } if (!pdata->clkin) { - clk = devm_clk_get(&spi->dev, "clkin"); + clk = devm_clk_get_enabled(&spi->dev, "clkin"); if (IS_ERR(clk)) - return -EPROBE_DEFER; - - ret = clk_prepare_enable(clk); - if (ret < 0) - return ret; + return PTR_ERR(clk); } indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_disable_clk; - } + if (indio_dev == NULL) + return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get(&spi->dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - goto error_disable_clk; - } + ret = devm_regulator_get_enable(&spi->dev, "vcc"); + if (ret) + return ret; - spi_set_drvdata(spi, indio_dev); st->spi = spi; st->pdata = pdata; @@ -544,47 +542,21 @@ static int adf4350_probe(struct spi_device *spi) st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL, GPIOD_IN); - if (IS_ERR(st->lock_detect_gpiod)) { - ret = PTR_ERR(st->lock_detect_gpiod); - goto error_disable_reg; - } + if (IS_ERR(st->lock_detect_gpiod)) + return PTR_ERR(st->lock_detect_gpiod); if (pdata->power_up_frequency) { ret = adf4350_set_freq(st, pdata->power_up_frequency); if (ret) - goto error_disable_reg; + return ret; } - ret = iio_device_register(indio_dev); + ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev); if (ret) - goto error_disable_reg; - - return 0; - -error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); -error_disable_clk: - clk_disable_unprepare(clk); - - return ret; -} - -static void adf4350_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adf4350_state *st = iio_priv(indio_dev); - struct regulator *reg = st->reg; - - st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN; - adf4350_sync_config(st); - - iio_device_unregister(indio_dev); - - clk_disable_unprepare(st->clk); + return dev_err_probe(&spi->dev, ret, + "Failed to add action to managed power down\n"); - if (!IS_ERR(reg)) - regulator_disable(reg); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct of_device_id adf4350_of_match[] = { @@ -607,7 +579,6 @@ static struct spi_driver adf4350_driver = { .of_match_table = adf4350_of_match, }, .probe = adf4350_probe, - .remove = adf4350_remove, .id_table = adf4350_id, }; module_spi_driver(adf4350_driver); diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index 698c50da1f10..59a38bf9459b 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -359,7 +359,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_gyro_3d_remove(struct platform_device *pdev) +static void hid_gyro_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -368,8 +368,6 @@ static int hid_gyro_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); - - return 0; } static const struct platform_device_id hid_gyro_3d_ids[] = { @@ -388,7 +386,7 @@ static struct platform_driver hid_gyro_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_gyro_3d_probe, - .remove = hid_gyro_3d_remove, + .remove_new = hid_gyro_3d_remove, }; module_platform_driver(hid_gyro_3d_platform_driver); diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index fa0fe404a70a..bf6d2636a85e 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -260,7 +260,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_humidity_remove(struct platform_device *pdev) +static void hid_humidity_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -269,8 +269,6 @@ static int hid_humidity_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY); hid_sensor_remove_trigger(indio_dev, &humid_st->common_attributes); - - return 0; } static const struct platform_device_id hid_humidity_ids[] = { @@ -289,7 +287,7 @@ static struct platform_driver hid_humidity_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_humidity_probe, - .remove = hid_humidity_remove, + .remove_new = hid_humidity_remove, }; module_platform_driver(hid_humidity_platform_driver); diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c index ebfb79bc9edc..9465908cc65e 100644 --- a/drivers/iio/humidity/si7005.c +++ b/drivers/iio/humidity/si7005.c @@ -169,9 +169,16 @@ static const struct i2c_device_id si7005_id[] = { }; MODULE_DEVICE_TABLE(i2c, si7005_id); +static const struct of_device_id si7005_dt_ids[] = { + { .compatible = "silabs,si7005" }, + { } +}; +MODULE_DEVICE_TABLE(of, si7005_dt_ids); + static struct i2c_driver si7005_driver = { .driver = { .name = "si7005", + .of_match_table = si7005_dt_ids, }, .probe = si7005_probe, .id_table = si7005_id, diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 501e286702ef..1a38b1915e7a 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -30,9 +30,6 @@ struct iio_ioctl_handler { unsigned int cmd, unsigned long arg); }; -long iio_device_ioctl(struct iio_dev *indio_dev, struct file *filp, - unsigned int cmd, unsigned long arg); - void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, struct iio_ioctl_handler *h); void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h); diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 17275a53ca2c..b7cbe1565aee 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -31,6 +31,12 @@ #define ADIS16475_REG_Y_ACCEL_L 0x14 #define ADIS16475_REG_Z_ACCEL_L 0x18 #define ADIS16475_REG_TEMP_OUT 0x1c +#define ADIS16475_REG_X_DELTANG_L 0x24 +#define ADIS16475_REG_Y_DELTANG_L 0x28 +#define ADIS16475_REG_Z_DELTANG_L 0x2C +#define ADIS16475_REG_X_DELTVEL_L 0x30 +#define ADIS16475_REG_Y_DELTVEL_L 0x34 +#define ADIS16475_REG_Z_DELTVEL_L 0x38 #define ADIS16475_REG_X_GYRO_BIAS_L 0x40 #define ADIS16475_REG_Y_GYRO_BIAS_L 0x44 #define ADIS16475_REG_Z_GYRO_BIAS_L 0x48 @@ -55,6 +61,7 @@ #define ADIS16475_REG_PROD_ID 0x72 #define ADIS16475_REG_SERIAL_NUM 0x74 #define ADIS16475_REG_FLASH_CNT 0x7c +#define ADIS16500_BURST_DATA_SEL_MASK BIT(8) #define ADIS16500_BURST32_MASK BIT(9) #define ADIS16500_BURST32(x) FIELD_PREP(ADIS16500_BURST32_MASK, x) /* number of data elements in burst mode */ @@ -65,6 +72,8 @@ #define ADIS16475_BURST_MAX_SPEED 1000000 #define ADIS16475_LSB_DEC_MASK BIT(0) #define ADIS16475_LSB_FIR_MASK BIT(1) +#define ADIS16500_BURST_DATA_SEL_0_CHN_MASK GENMASK(5, 0) +#define ADIS16500_BURST_DATA_SEL_1_CHN_MASK GENMASK(12, 7) enum { ADIS16475_SYNC_DIRECT = 1, @@ -84,16 +93,20 @@ struct adis16475_chip_info { const struct adis16475_sync *sync; const struct adis_data adis_data; const char *name; +#define ADIS16475_HAS_BURST32 BIT(0) +#define ADIS16475_HAS_BURST_DELTA_DATA BIT(1) + const long flags; u32 num_channels; u32 gyro_max_val; u32 gyro_max_scale; u32 accel_max_val; u32 accel_max_scale; u32 temp_scale; + u32 deltang_max_val; + u32 deltvel_max_val; u32 int_clk; u16 max_dec; u8 num_sync; - bool has_burst32; }; struct adis16475 { @@ -115,6 +128,12 @@ enum { ADIS16475_SCAN_ACCEL_Y, ADIS16475_SCAN_ACCEL_Z, ADIS16475_SCAN_TEMP, + ADIS16475_SCAN_DELTANG_X, + ADIS16475_SCAN_DELTANG_Y, + ADIS16475_SCAN_DELTANG_Z, + ADIS16475_SCAN_DELTVEL_X, + ADIS16475_SCAN_DELTVEL_Y, + ADIS16475_SCAN_DELTVEL_Z, }; static bool low_rate_allow; @@ -451,6 +470,14 @@ static int adis16475_read_raw(struct iio_dev *indio_dev, case IIO_TEMP: *val = st->info->temp_scale; return IIO_VAL_INT; + case IIO_DELTA_ANGL: + *val = st->info->deltang_max_val; + *val2 = 31; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_DELTA_VELOCITY: + *val = st->info->deltvel_max_val; + *val2 = 31; + return IIO_VAL_FRACTIONAL_LOG2; default: return -EINVAL; } @@ -551,6 +578,57 @@ static int adis16475_write_raw(struct iio_dev *indio_dev, }, \ } +#define ADIS16475_MOD_CHAN_DELTA(_type, _mod, _address, _si, _r_bits, _s_bits) { \ + .type = (_type), \ + .modified = 1, \ + .channel2 = (_mod), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .address = (_address), \ + .scan_index = _si, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (_r_bits), \ + .storagebits = (_s_bits), \ + .endianness = IIO_BE, \ + }, \ + } + +#define ADIS16475_DELTANG_CHAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTANG_L, ADIS16475_SCAN_DELTANG_ ## _mod, 32, 32) + +#define ADIS16475_DELTVEL_CHAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTVEL_L, ADIS16475_SCAN_DELTVEL_ ## _mod, 32, 32) + +#define ADIS16475_DELTANG_CHAN_NO_SCAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_ANGL, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTANG_L, -1, 32, 32) + +#define ADIS16475_DELTVEL_CHAN_NO_SCAN(_mod) \ + ADIS16475_MOD_CHAN_DELTA(IIO_DELTA_VELOCITY, IIO_MOD_ ## _mod, \ + ADIS16475_REG_ ## _mod ## _DELTVEL_L, -1, 32, 32) + +static const struct iio_chan_spec adis16477_channels[] = { + ADIS16475_GYRO_CHANNEL(X), + ADIS16475_GYRO_CHANNEL(Y), + ADIS16475_GYRO_CHANNEL(Z), + ADIS16475_ACCEL_CHANNEL(X), + ADIS16475_ACCEL_CHANNEL(Y), + ADIS16475_ACCEL_CHANNEL(Z), + ADIS16475_TEMP_CHANNEL(), + ADIS16475_DELTANG_CHAN(X), + ADIS16475_DELTANG_CHAN(Y), + ADIS16475_DELTANG_CHAN(Z), + ADIS16475_DELTVEL_CHAN(X), + ADIS16475_DELTVEL_CHAN(Y), + ADIS16475_DELTVEL_CHAN(Z), + IIO_CHAN_SOFT_TIMESTAMP(13) +}; + static const struct iio_chan_spec adis16475_channels[] = { ADIS16475_GYRO_CHANNEL(X), ADIS16475_GYRO_CHANNEL(Y), @@ -559,6 +637,12 @@ static const struct iio_chan_spec adis16475_channels[] = { ADIS16475_ACCEL_CHANNEL(Y), ADIS16475_ACCEL_CHANNEL(Z), ADIS16475_TEMP_CHANNEL(), + ADIS16475_DELTANG_CHAN_NO_SCAN(X), + ADIS16475_DELTANG_CHAN_NO_SCAN(Y), + ADIS16475_DELTANG_CHAN_NO_SCAN(Z), + ADIS16475_DELTVEL_CHAN_NO_SCAN(X), + ADIS16475_DELTVEL_CHAN_NO_SCAN(Y), + ADIS16475_DELTVEL_CHAN_NO_SCAN(Z), IIO_CHAN_SOFT_TIMESTAMP(7) }; @@ -662,6 +746,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -677,6 +763,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -692,6 +780,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -707,6 +797,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -715,50 +807,56 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16477_1] = { .name = "adis16477-1", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16), .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), }, [ADIS16477_2] = { .name = "adis16477-2", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), }, [ADIS16477_3] = { .name = "adis16477-3", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, .num_sync = ARRAY_SIZE(adis16475_sync_mode), - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16477, &adis16475_timeouts), }, [ADIS16465_1] = { @@ -770,6 +868,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -785,6 +885,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -800,6 +902,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(4000 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -815,6 +919,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -830,6 +936,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -845,6 +953,8 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { .accel_max_val = 1, .accel_max_scale = IIO_M_S_2_TO_G(800 << 16), .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, @@ -853,129 +963,168 @@ static const struct adis16475_chip_info adis16475_chip_info[] = { }, [ADIS16500] = { .name = "adis16500", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16500, &adis1650x_timeouts), }, [ADIS16505_1] = { .name = "adis16505-1", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16), .accel_max_val = 78, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), }, [ADIS16505_2] = { .name = "adis16505-2", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), .accel_max_val = 78, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), }, [ADIS16505_3] = { .name = "adis16505-3", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 78, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 100, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16505, &adis1650x_timeouts), }, [ADIS16507_1] = { .name = "adis16507-1", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(160 << 16), .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(360), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), }, [ADIS16507_2] = { .name = "adis16507-2", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(40 << 16), .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(720), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), }, [ADIS16507_3] = { .name = "adis16507-3", - .num_channels = ARRAY_SIZE(adis16475_channels), - .channels = adis16475_channels, + .num_channels = ARRAY_SIZE(adis16477_channels), + .channels = adis16477_channels, .gyro_max_val = 1, .gyro_max_scale = IIO_RAD_TO_DEGREE(10 << 16), .accel_max_val = 392, .accel_max_scale = 32000 << 16, .temp_scale = 100, + .deltang_max_val = IIO_DEGREE_TO_RAD(2160), + .deltvel_max_val = 400, .int_clk = 2000, .max_dec = 1999, .sync = adis16475_sync_mode, /* pulse sync not supported */ .num_sync = ARRAY_SIZE(adis16475_sync_mode) - 1, - .has_burst32 = true, + .flags = ADIS16475_HAS_BURST32 | ADIS16475_HAS_BURST_DELTA_DATA, .adis_data = ADIS16475_DATA(16507, &adis1650x_timeouts), }, }; +static int adis16475_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + u16 en; + int ret; + struct adis16475 *st = iio_priv(indio_dev); + + if (st->info->flags & ADIS16475_HAS_BURST_DELTA_DATA) { + if ((*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK) && + (*scan_mask & ADIS16500_BURST_DATA_SEL_1_CHN_MASK)) + return -EINVAL; + if (*scan_mask & ADIS16500_BURST_DATA_SEL_0_CHN_MASK) + en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 0); + else + en = FIELD_PREP(ADIS16500_BURST_DATA_SEL_MASK, 1); + + ret = __adis_update_bits(&st->adis, ADIS16475_REG_MSG_CTRL, + ADIS16500_BURST_DATA_SEL_MASK, en); + if (ret) + return ret; + } + + return adis_update_scan_mode(indio_dev, scan_mask); +} + static const struct iio_info adis16475_info = { .read_raw = &adis16475_read_raw, .write_raw = &adis16475_write_raw, - .update_scan_mode = adis_update_scan_mode, + .update_scan_mode = adis16475_update_scan_mode, .debugfs_reg_access = adis_debugfs_reg_access, }; @@ -998,7 +1147,7 @@ static void adis16475_burst32_check(struct adis16475 *st) int ret; struct adis *adis = &st->adis; - if (!st->info->has_burst32) + if (!(st->info->flags & ADIS16475_HAS_BURST32)) return; if (st->lsb_flag && !st->burst32) { @@ -1044,7 +1193,7 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct adis16475 *st = iio_priv(indio_dev); struct adis *adis = &st->adis; - int ret, bit, i = 0; + int ret, bit, buff_offset = 0, i = 0; __be16 *buffer; u16 crc; bool valid; @@ -1073,7 +1222,20 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) switch (bit) { case ADIS16475_SCAN_TEMP: st->data[i++] = buffer[offset]; + /* + * The temperature channel has 16-bit storage size. + * We need to perform the padding to have the buffer + * elements naturally aligned in case there are any + * 32-bit storage size channels enabled which have a + * scan index higher than the temperature channel scan + * index. + */ + if (*indio_dev->active_scan_mask & GENMASK(ADIS16475_SCAN_DELTVEL_Z, ADIS16475_SCAN_DELTANG_X)) + st->data[i++] = 0; break; + case ADIS16475_SCAN_DELTANG_X ... ADIS16475_SCAN_DELTVEL_Z: + buff_offset = ADIS16475_SCAN_DELTANG_X; + fallthrough; case ADIS16475_SCAN_GYRO_X ... ADIS16475_SCAN_ACCEL_Z: /* * The first 2 bytes on the received data are the @@ -1081,18 +1243,18 @@ static irqreturn_t adis16475_trigger_handler(int irq, void *p) */ if (st->burst32) { /* upper 16 */ - st->data[i++] = buffer[bit * 2 + 2]; + st->data[i++] = buffer[(bit - buff_offset) * 2 + 2]; /* lower 16 */ - st->data[i++] = buffer[bit * 2 + 1]; + st->data[i++] = buffer[(bit - buff_offset) * 2 + 1]; } else { - st->data[i++] = buffer[bit + 1]; + st->data[i++] = buffer[(bit - buff_offset) + 1]; /* * Don't bother in doing the manual read if the * device supports burst32. burst32 will be * enabled in the next call to * adis16475_burst32_check()... */ - if (st->lsb_flag && !st->info->has_burst32) { + if (st->lsb_flag && !(st->info->flags & ADIS16475_HAS_BURST32)) { u16 val = 0; const u32 reg = ADIS16475_REG_X_GYRO_L + bit * 4; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c index 7327e5723f96..8a7f2911905a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c @@ -71,6 +71,19 @@ int inv_mpu_aux_init(const struct inv_mpu6050_state *st) unsigned int val; int ret; + /* + * Code based on the vendor Linux kernel v3.0, + * the exact meaning is unknown. + */ + if (st->chip_type == INV_MPU9150) { + unsigned int mask = BIT(7); + + val = st->level_shifter ? mask : 0; + ret = regmap_update_bits(st->map, 0x1, mask, val); + if (ret) + return ret; + } + /* configure i2c master */ val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ | INV_MPU6050_BIT_WAIT_FOR_ES; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 29f906c884bd..3fbeef1a7018 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -17,6 +17,7 @@ #include <linux/regulator/consumer.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/iio/common/inv_sensors_timestamp.h> #include <linux/iio/iio.h> @@ -1495,6 +1496,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, st->irq = irq; st->map = regmap; + st->level_shifter = device_property_read_bool(dev, + "invensense,level-shifter"); pdata = dev_get_platdata(dev); if (!pdata) { result = iio_read_mount_matrix(dev, &st->orientation); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index ed5a96e78df0..5950e2419ebb 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -203,6 +203,7 @@ struct inv_mpu6050_state { s32 magn_raw_to_gauss[3]; struct iio_mount_matrix magn_orient; unsigned int suspended_sensors; + bool level_shifter; u8 *data; }; @@ -464,7 +465,6 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type); int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable); int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, unsigned int mask); -int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); int inv_mpu_acpi_create_mux_client(struct i2c_client *client); void inv_mpu_acpi_delete_mux_client(struct i2c_client *client); int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index d752e9c0499b..c77745b594bd 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -90,6 +90,10 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", + [IIO_DELTA_ANGL] = "deltaangl", + [IIO_DELTA_VELOCITY] = "deltavelocity", + [IIO_COLORTEMP] = "colortemp", + [IIO_CHROMATICITY] = "chromaticity", }; static const char * const iio_modifier_names[] = { diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 19f7a91157ee..910c1f14abd5 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -355,6 +355,21 @@ static ssize_t iio_ev_value_store(struct device *dev, return len; } +static ssize_t iio_ev_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + if (indio_dev->info->read_event_label) + return indio_dev->info->read_event_label(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), buf); + + return -EINVAL; +} + static int iio_device_add_event(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int spec_index, enum iio_event_type type, enum iio_event_direction dir, @@ -411,6 +426,41 @@ static int iio_device_add_event(struct iio_dev *indio_dev, return attrcount; } +static int iio_device_add_event_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int spec_index, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + char *postfix; + int ret; + + if (!indio_dev->info->read_event_label) + return 0; + + if (dir != IIO_EV_DIR_NONE) + postfix = kasprintf(GFP_KERNEL, "%s_%s_label", + iio_ev_type_text[type], + iio_ev_dir_text[dir]); + else + postfix = kasprintf(GFP_KERNEL, "%s_label", + iio_ev_type_text[type]); + if (postfix == NULL) + return -ENOMEM; + + ret = __iio_add_chan_devattr(postfix, chan, &iio_ev_label_show, NULL, + spec_index, IIO_SEPARATE, &indio_dev->dev, NULL, + &iio_dev_opaque->event_interface->dev_attr_list); + + kfree(postfix); + + if (ret < 0) + return ret; + + return 1; +} + static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, struct iio_chan_spec const *chan) { @@ -448,6 +498,11 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, if (ret < 0) return ret; attrcount += ret; + + ret = iio_device_add_event_label(indio_dev, chan, i, type, dir); + if (ret < 0) + return ret; + attrcount += ret; } ret = attrcount; return ret; diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c index e7f0b81b7f5a..22a63a89f289 100644 --- a/drivers/iio/light/cm3605.c +++ b/drivers/iio/light/cm3605.c @@ -266,7 +266,7 @@ out_disable_vdd: return ret; } -static int cm3605_remove(struct platform_device *pdev) +static void cm3605_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct cm3605 *cm3605 = iio_priv(indio_dev); @@ -276,8 +276,6 @@ static int cm3605_remove(struct platform_device *pdev) gpiod_set_value_cansleep(cm3605->aset, 0); iio_device_unregister(indio_dev); regulator_disable(cm3605->vdd); - - return 0; } static int cm3605_pm_suspend(struct device *dev) @@ -320,7 +318,7 @@ static struct platform_driver cm3605_driver = { .pm = pm_sleep_ptr(&cm3605_dev_pm_ops), }, .probe = cm3605_probe, - .remove = cm3605_remove, + .remove_new = cm3605_remove, }; module_platform_driver(cm3605_driver); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index eb1aedad7edc..f17304b54468 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -14,8 +14,11 @@ #include "../common/hid-sensors/hid-sensor-trigger.h" enum { - CHANNEL_SCAN_INDEX_INTENSITY = 0, - CHANNEL_SCAN_INDEX_ILLUM = 1, + CHANNEL_SCAN_INDEX_INTENSITY, + CHANNEL_SCAN_INDEX_ILLUM, + CHANNEL_SCAN_INDEX_COLOR_TEMP, + CHANNEL_SCAN_INDEX_CHROMATICITY_X, + CHANNEL_SCAN_INDEX_CHROMATICITY_Y, CHANNEL_SCAN_INDEX_MAX }; @@ -24,7 +27,7 @@ enum { struct als_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; - struct hid_sensor_hub_attribute_info als_illum; + struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX]; struct { u32 illum[CHANNEL_SCAN_INDEX_MAX]; u64 timestamp __aligned(8); @@ -65,6 +68,40 @@ static const struct iio_chan_spec als_channels[] = { BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), .scan_index = CHANNEL_SCAN_INDEX_ILLUM, }, + { + .type = IIO_COLORTEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP, + }, + { + .type = IIO_CHROMATICITY, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X, + }, + { + .type = IIO_CHROMATICITY, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS) | + BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE), + .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_Y, + }, IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; @@ -99,10 +136,25 @@ static int als_read_raw(struct iio_dev *indio_dev, switch (chan->scan_index) { case CHANNEL_SCAN_INDEX_INTENSITY: case CHANNEL_SCAN_INDEX_ILLUM: - report_id = als_state->als_illum.report_id; - min = als_state->als_illum.logical_minimum; + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; address = HID_USAGE_SENSOR_LIGHT_ILLUM; break; + case CHANNEL_SCAN_INDEX_COLOR_TEMP: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE; + break; + case CHANNEL_SCAN_INDEX_CHROMATICITY_X: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X; + break; + case CHANNEL_SCAN_INDEX_CHROMATICITY_Y: + report_id = als_state->als[chan->scan_index].report_id; + min = als_state->als[chan->scan_index].logical_minimum; + address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y; + break; default: report_id = -1; break; @@ -223,6 +275,18 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data; ret = 0; break; + case HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE: + als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data; + ret = 0; + break; + case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X: + als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_X] = sample_data; + ret = 0; + break; + case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y: + als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_Y] = sample_data; + ret = 0; + break; case HID_USAGE_SENSOR_TIME_TIMESTAMP: als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes, *(s64 *)raw_data); @@ -242,22 +306,56 @@ static int als_parse_report(struct platform_device *pdev, struct als_state *st) { int ret; + int i; + + for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) { + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_LIGHT_ILLUM, + &st->als[i]); + if (ret < 0) + return ret; + als_adjust_channel_bit_mask(channels, i, st->als[i].size); + + dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index, + st->als[i].report_id); + } ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, - usage_id, - HID_USAGE_SENSOR_LIGHT_ILLUM, - &st->als_illum); + usage_id, + HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE, + &st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP]); if (ret < 0) return ret; - als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_INTENSITY, - st->als_illum.size); - als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM, - st->als_illum.size); - - dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, - st->als_illum.report_id); + als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_COLOR_TEMP, + st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].size); + + dev_dbg(&pdev->dev, "als %x:%x\n", + st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].index, + st->als[CHANNEL_SCAN_INDEX_COLOR_TEMP].report_id); + + for (i = 0; i < 2; i++) { + int next_scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X + i; + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, usage_id, + HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X + i, + &st->als[next_scan_index]); + if (ret < 0) + return ret; + + als_adjust_channel_bit_mask(channels, + CHANNEL_SCAN_INDEX_CHROMATICITY_X + i, + st->als[next_scan_index].size); + + dev_dbg(&pdev->dev, "als %x:%x\n", + st->als[next_scan_index].index, + st->als[next_scan_index].report_id); + } - st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum, + st->scale_precision = hid_sensor_format_scale(usage_id, + &st->als[CHANNEL_SCAN_INDEX_INTENSITY], &st->scale_pre_decml, &st->scale_post_decml); return ret; @@ -347,7 +445,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_als_remove(struct platform_device *pdev) +static void hid_als_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -356,8 +454,6 @@ static int hid_als_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); - - return 0; } static const struct platform_device_id hid_als_ids[] = { @@ -380,7 +476,7 @@ static struct platform_driver hid_als_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_als_probe, - .remove = hid_als_remove, + .remove_new = hid_als_remove, }; module_platform_driver(hid_als_platform_driver); diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index a47591e1bad9..26c481d2998c 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -313,7 +313,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_prox_remove(struct platform_device *pdev) +static void hid_prox_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -322,8 +322,6 @@ static int hid_prox_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); - - return 0; } static const struct platform_device_id hid_prox_ids[] = { @@ -346,7 +344,7 @@ static struct platform_driver hid_prox_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_prox_probe, - .remove = hid_prox_remove, + .remove_new = hid_prox_remove, }; module_platform_driver(hid_prox_platform_driver); diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index 827bc25269e9..7800f7fa51b7 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -895,7 +895,7 @@ err_free_irq: return ret; } -static int lm3533_als_remove(struct platform_device *pdev) +static void lm3533_als_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct lm3533_als *als = iio_priv(indio_dev); @@ -905,8 +905,6 @@ static int lm3533_als_remove(struct platform_device *pdev) lm3533_als_disable(als); if (als->irq) free_irq(als->irq, indio_dev); - - return 0; } static struct platform_driver lm3533_als_driver = { @@ -914,7 +912,7 @@ static struct platform_driver lm3533_als_driver = { .name = "lm3533-als", }, .probe = lm3533_als_probe, - .remove = lm3533_als_remove, + .remove_new = lm3533_als_remove, }; module_platform_driver(lm3533_als_driver); diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c index 502946bf9f94..6cf60151b3d8 100644 --- a/drivers/iio/light/opt4001.c +++ b/drivers/iio/light/opt4001.c @@ -412,7 +412,7 @@ static int opt4001_probe(struct i2c_client *client) if (dev_id != OPT4001_DEVICE_ID_VAL) dev_warn(&client->dev, "Device ID: %#04x unknown\n", dev_id); - chip->chip_info = device_get_match_data(&client->dev); + chip->chip_info = i2c_get_match_data(client); indio_dev->channels = opt4001_channels; indio_dev->num_channels = ARRAY_SIZE(opt4001_channels); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index eb706d0bf70b..dd466c5fa621 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -204,7 +204,6 @@ static long ak09912_raw_to_gauss(u16 data) /* Compatible Asahi Kasei Compass parts */ enum asahi_compass_chipset { - AKXXXX = 0, AK8975, AK8963, AK09911, @@ -248,7 +247,7 @@ struct ak_def { }; static const struct ak_def ak_def_array[] = { - { + [AK8975] = { .type = AK8975, .raw_to_gauss = ak8975_raw_to_gauss, .range = 4096, @@ -273,7 +272,7 @@ static const struct ak_def ak_def_array[] = { AK8975_REG_HYL, AK8975_REG_HZL}, }, - { + [AK8963] = { .type = AK8963, .raw_to_gauss = ak8963_09911_raw_to_gauss, .range = 8190, @@ -298,7 +297,7 @@ static const struct ak_def ak_def_array[] = { AK8975_REG_HYL, AK8975_REG_HZL}, }, - { + [AK09911] = { .type = AK09911, .raw_to_gauss = ak8963_09911_raw_to_gauss, .range = 8192, @@ -323,7 +322,7 @@ static const struct ak_def ak_def_array[] = { AK09912_REG_HYL, AK09912_REG_HZL}, }, - { + [AK09912] = { .type = AK09912, .raw_to_gauss = ak09912_raw_to_gauss, .range = 32752, @@ -348,7 +347,7 @@ static const struct ak_def ak_def_array[] = { AK09912_REG_HYL, AK09912_REG_HZL}, }, - { + [AK09916] = { .type = AK09916, .raw_to_gauss = ak09912_raw_to_gauss, .range = 32752, @@ -812,18 +811,6 @@ static const struct iio_info ak8975_info = { .read_raw = &ak8975_read_raw, }; -static const struct acpi_device_id ak_acpi_match[] = { - {"AK8975", AK8975}, - {"AK8963", AK8963}, - {"INVN6500", AK8963}, - {"AK009911", AK09911}, - {"AK09911", AK09911}, - {"AKM9911", AK09911}, - {"AK09912", AK09912}, - { } -}; -MODULE_DEVICE_TABLE(acpi, ak_acpi_match); - static void ak8975_fill_buffer(struct iio_dev *indio_dev) { struct ak8975_data *data = iio_priv(indio_dev); @@ -883,10 +870,7 @@ static int ak8975_probe(struct i2c_client *client) struct iio_dev *indio_dev; struct gpio_desc *eoc_gpiod; struct gpio_desc *reset_gpiod; - const void *match; - unsigned int i; int err; - enum asahi_compass_chipset chipset; const char *name = NULL; /* @@ -928,27 +912,15 @@ static int ak8975_probe(struct i2c_client *client) return err; /* id will be NULL when enumerated via ACPI */ - match = device_get_match_data(&client->dev); - if (match) { - chipset = (uintptr_t)match; - name = dev_name(&client->dev); - } else if (id) { - chipset = (enum asahi_compass_chipset)(id->driver_data); - name = id->name; - } else - return -ENOSYS; - - for (i = 0; i < ARRAY_SIZE(ak_def_array); i++) - if (ak_def_array[i].type == chipset) - break; - - if (i == ARRAY_SIZE(ak_def_array)) { - dev_err(&client->dev, "AKM device type unsupported: %d\n", - chipset); + data->def = i2c_get_match_data(client); + if (!data->def) return -ENODEV; - } - data->def = &ak_def_array[i]; + /* If enumerated via firmware node, fix the ABI */ + if (dev_fwnode(&client->dev)) + name = dev_name(&client->dev); + else + name = id->name; /* Fetch the regulators */ data->vdd = devm_regulator_get(&client->dev, "vdd"); @@ -1076,29 +1048,40 @@ static int ak8975_runtime_resume(struct device *dev) static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend, ak8975_runtime_resume, NULL); +static const struct acpi_device_id ak_acpi_match[] = { + {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"AK8975", (kernel_ulong_t)&ak_def_array[AK8975] }, + {"AK009911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"AK09911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"AK09912", (kernel_ulong_t)&ak_def_array[AK09912] }, + {"AKM9911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"INVN6500", (kernel_ulong_t)&ak_def_array[AK8963] }, + { } +}; +MODULE_DEVICE_TABLE(acpi, ak_acpi_match); + static const struct i2c_device_id ak8975_id[] = { - {"ak8975", AK8975}, - {"ak8963", AK8963}, - {"AK8963", AK8963}, - {"ak09911", AK09911}, - {"ak09912", AK09912}, - {"ak09916", AK09916}, + {"AK8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"ak8963", (kernel_ulong_t)&ak_def_array[AK8963] }, + {"ak8975", (kernel_ulong_t)&ak_def_array[AK8975] }, + {"ak09911", (kernel_ulong_t)&ak_def_array[AK09911] }, + {"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] }, + {"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] }, {} }; - MODULE_DEVICE_TABLE(i2c, ak8975_id); static const struct of_device_id ak8975_of_match[] = { - { .compatible = "asahi-kasei,ak8975", }, - { .compatible = "ak8975", }, - { .compatible = "asahi-kasei,ak8963", }, - { .compatible = "ak8963", }, - { .compatible = "asahi-kasei,ak09911", }, - { .compatible = "ak09911", }, - { .compatible = "asahi-kasei,ak09912", }, - { .compatible = "ak09912", }, - { .compatible = "asahi-kasei,ak09916", }, - { .compatible = "ak09916", }, + { .compatible = "asahi-kasei,ak8975", .data = &ak_def_array[AK8975] }, + { .compatible = "ak8975", .data = &ak_def_array[AK8975] }, + { .compatible = "asahi-kasei,ak8963", .data = &ak_def_array[AK8963] }, + { .compatible = "ak8963", .data = &ak_def_array[AK8963] }, + { .compatible = "asahi-kasei,ak09911", .data = &ak_def_array[AK09911] }, + { .compatible = "ak09911", .data = &ak_def_array[AK09911] }, + { .compatible = "asahi-kasei,ak09912", .data = &ak_def_array[AK09912] }, + { .compatible = "ak09912", .data = &ak_def_array[AK09912] }, + { .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] }, + { .compatible = "ak09916", .data = &ak_def_array[AK09916] }, {} }; MODULE_DEVICE_TABLE(of, ak8975_of_match); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index e85a3a8eea90..5c795a430d09 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -547,7 +547,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_magn_3d_remove(struct platform_device *pdev) +static void hid_magn_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -556,8 +556,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &magn_state->magn_flux_attributes); - - return 0; } static const struct platform_device_id hid_magn_3d_ids[] = { @@ -576,7 +574,7 @@ static struct platform_driver hid_magn_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_magn_3d_probe, - .remove = hid_magn_3d_remove, + .remove_new = hid_magn_3d_remove, }; module_platform_driver(hid_magn_3d_platform_driver); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index c5e485bfc6fc..7b041bb38693 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -1434,9 +1434,7 @@ static int yas5xx_probe(struct i2c_client *i2c) goto assert_reset; } - ci = device_get_match_data(dev); - if (!ci) - ci = (const struct yas5xx_chip_info *)id->driver_data; + ci = i2c_get_match_data(i2c); yas5xx->chip_info = ci; ret = regmap_read(yas5xx->map, YAS5XX_DEVICE_ID, &id_check); diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index ba5b581d5b25..8943d5c78bc0 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -383,7 +383,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_incl_3d_remove(struct platform_device *pdev) +static void hid_incl_3d_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -392,8 +392,6 @@ static int hid_incl_3d_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); - - return 0; } static const struct platform_device_id hid_incl_3d_ids[] = { @@ -412,7 +410,7 @@ static struct platform_driver hid_incl_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_incl_3d_probe, - .remove = hid_incl_3d_remove, + .remove_new = hid_incl_3d_remove, }; module_platform_driver(hid_incl_3d_platform_driver); diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index a033699910e8..5e8cadd5177a 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -327,7 +327,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_dev_rot_remove(struct platform_device *pdev) +static void hid_dev_rot_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -336,8 +336,6 @@ static int hid_dev_rot_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &rot_state->common_attributes); - - return 0; } static const struct platform_device_id hid_dev_rot_ids[] = { @@ -364,7 +362,7 @@ static struct platform_driver hid_dev_rot_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_dev_rot_probe, - .remove = hid_dev_rot_remove, + .remove_new = hid_dev_rot_remove, }; module_platform_driver(hid_dev_rot_platform_driver); diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index 07c30d217255..76e173850a35 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -342,7 +342,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_hinge_remove(struct platform_device *pdev) +static void hid_hinge_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -351,8 +351,6 @@ static int hid_hinge_remove(struct platform_device *pdev) iio_device_unregister(indio_dev); sensor_hub_remove_callback(hsdev, hsdev->usage); hid_sensor_remove_trigger(indio_dev, &st->common_attributes); - - return 0; } static const struct platform_device_id hid_hinge_ids[] = { @@ -371,7 +369,7 @@ static struct platform_driver hid_hinge_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_hinge_probe, - .remove = hid_hinge_remove, + .remove_new = hid_hinge_remove, }; module_platform_driver(hid_hinge_platform_driver); diff --git a/drivers/iio/potentiometer/ad5110.c b/drivers/iio/potentiometer/ad5110.c index 991e745c4f93..aaf02cc7aeba 100644 --- a/drivers/iio/potentiometer/ad5110.c +++ b/drivers/iio/potentiometer/ad5110.c @@ -278,14 +278,19 @@ static const struct of_device_id ad5110_of_match[] = { }; MODULE_DEVICE_TABLE(of, ad5110_of_match); +#define AD5110_ID_TABLE(_name, cfg) { \ + .name = _name, \ + .driver_data = (kernel_ulong_t)&ad5110_cfg[cfg], \ +} + static const struct i2c_device_id ad5110_id[] = { - { "ad5110-10", AD5110_10 }, - { "ad5110-80", AD5110_80 }, - { "ad5112-05", AD5112_05 }, - { "ad5112-10", AD5112_10 }, - { "ad5112-80", AD5112_80 }, - { "ad5114-10", AD5114_10 }, - { "ad5114-80", AD5114_80 }, + AD5110_ID_TABLE("ad5110-10", AD5110_10), + AD5110_ID_TABLE("ad5110-80", AD5110_80), + AD5110_ID_TABLE("ad5112-05", AD5112_05), + AD5110_ID_TABLE("ad5112-10", AD5112_10), + AD5110_ID_TABLE("ad5112-80", AD5112_80), + AD5110_ID_TABLE("ad5114-10", AD5114_10), + AD5110_ID_TABLE("ad5114-80", AD5114_80), { } }; MODULE_DEVICE_TABLE(i2c, ad5110_id); @@ -305,7 +310,7 @@ static int ad5110_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); data->enable = 1; - data->cfg = device_get_match_data(dev); + data->cfg = i2c_get_match_data(client); /* refresh RDAC register with EEPROM */ ret = ad5110_write(data, AD5110_RESET, 0); diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index fc183e0790da..e0526dd0e3cb 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -204,7 +204,6 @@ static const struct iio_info ds1803_info = { static int ds1803_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device *dev = &client->dev; struct ds1803_data *data; struct iio_dev *indio_dev; @@ -217,9 +216,7 @@ static int ds1803_probe(struct i2c_client *client) data = iio_priv(indio_dev); data->client = client; - data->cfg = device_get_match_data(dev); - if (!data->cfg) - data->cfg = &ds1803_cfg[id->driver_data]; + data->cfg = i2c_get_match_data(client); indio_dev->info = &ds1803_info; indio_dev->channels = data->cfg->channels; @@ -239,10 +236,10 @@ static const struct of_device_id ds1803_dt_ids[] = { MODULE_DEVICE_TABLE(of, ds1803_dt_ids); static const struct i2c_device_id ds1803_id[] = { - { "ds1803-010", DS1803_010 }, - { "ds1803-050", DS1803_050 }, - { "ds1803-100", DS1803_100 }, - { "ds3502", DS3502 }, + { "ds1803-010", (kernel_ulong_t)&ds1803_cfg[DS1803_010] }, + { "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] }, + { "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] }, + { "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] }, {} }; MODULE_DEVICE_TABLE(i2c, ds1803_id); diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 7b4c2af32852..95efa32e4289 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -16,6 +16,15 @@ config ABP060MG To compile this driver as a module, choose M here: the module will be called abp060mg. +config ROHM_BM1390 + tristate "ROHM BM1390GLV-Z pressure sensor driver" + depends on I2C + help + Support for the ROHM BM1390 pressure sensor. The BM1390GLV-Z + can measure pressures ranging from 300 hPa to 1300 hPa with + configurable measurement averaging and internal FIFO. The + sensor does also provide temperature measurements. + config BMP280 tristate "Bosch Sensortec BMP180/BMP280/BMP380/BMP580 pressure sensor driver" depends on (I2C || SPI_MASTER) diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index c90f77210e94..436aec7e65f3 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ABP060MG) += abp060mg.o +obj-$(CONFIG_ROHM_BM1390) += rohm-bm1390.o obj-$(CONFIG_BMP280) += bmp280.o bmp280-objs := bmp280-core.o bmp280-regmap.o obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index a9215eb32d70..956045e2db29 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -323,7 +323,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_press_remove(struct platform_device *pdev) +static void hid_press_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -332,8 +332,6 @@ static int hid_press_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); - - return 0; } static const struct platform_device_id hid_press_ids[] = { @@ -352,7 +350,7 @@ static struct platform_driver hid_press_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_press_probe, - .remove = hid_press_remove, + .remove_new = hid_press_remove, }; module_platform_driver(hid_press_platform_driver); diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index 9b3abffb724b..ac30d76285d1 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -144,7 +144,6 @@ static const struct iio_info ms5637_info = { static int ms5637_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct ms_tp_data *data; struct ms_tp_dev *dev_data; struct iio_dev *indio_dev; @@ -159,10 +158,7 @@ static int ms5637_probe(struct i2c_client *client) return -EOPNOTSUPP; } - if (id) - data = (const struct ms_tp_data *)id->driver_data; - else - data = device_get_match_data(&client->dev); + data = i2c_get_match_data(client); if (!data) return -EINVAL; diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c new file mode 100644 index 000000000000..ccaa07a569c9 --- /dev/null +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -0,0 +1,934 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * BM1390 ROHM pressure sensor + * + * Copyright (c) 2023, ROHM Semiconductor. + * https://fscdn.rohm.com/en/products/databook/datasheet/ic/sensor/pressure/bm1390glv-z-e.pdf + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define BM1390_REG_MANUFACT_ID 0x0f +#define BM1390_REG_PART_ID 0x10 +#define BM1390_REG_POWER 0x12 +#define BM1390_MASK_POWER BIT(0) +#define BM1390_POWER_ON BM1390_MASK_POWER +#define BM1390_POWER_OFF 0x00 +#define BM1390_REG_RESET 0x13 +#define BM1390_MASK_RESET BIT(0) +#define BM1390_RESET_RELEASE BM1390_MASK_RESET +#define BM1390_RESET 0x00 +#define BM1390_REG_MODE_CTRL 0x14 +#define BM1390_MASK_MEAS_MODE GENMASK(1, 0) +#define BM1390_MASK_DRDY_EN BIT(4) +#define BM1390_MASK_WMI_EN BIT(2) +#define BM1390_MASK_AVE_NUM GENMASK(7, 5) + +/* + * Data-sheet states that when the IIR is used, the AVE_NUM must be set to + * value 110b + */ +#define BM1390_IIR_AVE_NUM 0x06 +#define BM1390_REG_FIFO_CTRL 0x15 +#define BM1390_MASK_IIR_MODE GENMASK(1, 0) +#define BM1390_IIR_MODE_OFF 0x0 +#define BM1390_IIR_MODE_WEAK 0x1 +#define BM1390_IIR_MODE_MID 0x2 +#define BM1390_IIR_MODE_STRONG 0x3 + +#define BM1390_MASK_FIFO_LEN BIT(6) +#define BM1390_MASK_FIFO_EN BIT(7) +#define BM1390_WMI_MIN 2 +#define BM1390_WMI_MAX 3 + +#define BM1390_REG_FIFO_LVL 0x18 +#define BM1390_MASK_FIFO_LVL GENMASK(2, 0) +#define BM1390_REG_STATUS 0x19 +#define BM1390_REG_PRESSURE_BASE 0x1a +#define BM1390_REG_TEMP_HI 0x1d +#define BM1390_REG_TEMP_LO 0x1e +#define BM1390_MAX_REGISTER BM1390_REG_TEMP_LO + +#define BM1390_ID 0x34 + +/* Regmap configs */ +static const struct regmap_range bm1390_volatile_ranges[] = { + { + .range_min = BM1390_REG_STATUS, + .range_max = BM1390_REG_STATUS, + }, + { + .range_min = BM1390_REG_FIFO_LVL, + .range_max = BM1390_REG_TEMP_LO, + }, +}; + +static const struct regmap_access_table bm1390_volatile_regs = { + .yes_ranges = &bm1390_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bm1390_volatile_ranges), +}; + +static const struct regmap_range bm1390_precious_ranges[] = { + { + .range_min = BM1390_REG_STATUS, + .range_max = BM1390_REG_STATUS, + }, +}; + +static const struct regmap_access_table bm1390_precious_regs = { + .yes_ranges = &bm1390_precious_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bm1390_precious_ranges), +}; + +static const struct regmap_range bm1390_read_only_ranges[] = { + { + .range_min = BM1390_REG_MANUFACT_ID, + .range_max = BM1390_REG_PART_ID, + }, { + .range_min = BM1390_REG_FIFO_LVL, + .range_max = BM1390_REG_TEMP_LO, + }, +}; + +static const struct regmap_access_table bm1390_ro_regs = { + .no_ranges = &bm1390_read_only_ranges[0], + .n_no_ranges = ARRAY_SIZE(bm1390_read_only_ranges), +}; + +static const struct regmap_range bm1390_noinc_read_ranges[] = { + { + .range_min = BM1390_REG_PRESSURE_BASE, + .range_max = BM1390_REG_TEMP_LO, + }, +}; + +static const struct regmap_access_table bm1390_nir_regs = { + .yes_ranges = &bm1390_noinc_read_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bm1390_noinc_read_ranges), +}; + +static const struct regmap_config bm1390_regmap = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &bm1390_volatile_regs, + .wr_table = &bm1390_ro_regs, + .rd_noinc_table = &bm1390_nir_regs, + .precious_table = &bm1390_precious_regs, + .max_register = BM1390_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, + .disable_locking = true, +}; + +enum { + BM1390_STATE_SAMPLE, + BM1390_STATE_FIFO, +}; + +struct bm1390_data_buf { + u32 pressure; + __be16 temp; + s64 ts __aligned(8); +}; + +/* BM1390 has FIFO for 4 pressure samples */ +#define BM1390_FIFO_LENGTH 4 + +struct bm1390_data { + s64 timestamp, old_timestamp; + struct iio_trigger *trig; + struct regmap *regmap; + struct device *dev; + struct bm1390_data_buf buf; + int irq; + unsigned int state; + bool trigger_enabled; + u8 watermark; + + /* Prevent accessing sensor during FIFO read sequence */ + struct mutex mutex; +}; + +enum { + BM1390_CHAN_PRESSURE, + BM1390_CHAN_TEMP, +}; + +static const struct iio_chan_spec bm1390_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + /* + * When IIR is used, we must fix amount of averaged samples. + * Thus we don't allow setting oversampling ratio. + */ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .scan_index = BM1390_CHAN_PRESSURE, + .scan_type = { + .sign = 'u', + .realbits = 22, + .storagebits = 32, + .endianness = IIO_LE, + }, + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .scan_index = BM1390_CHAN_TEMP, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +/* + * We can't skip reading the pressure because the watermark IRQ is acked + * only when the pressure data is read from the FIFO. + */ +static const unsigned long bm1390_scan_masks[] = { + BIT(BM1390_CHAN_PRESSURE), + BIT(BM1390_CHAN_PRESSURE) | BIT(BM1390_CHAN_TEMP), + 0 +}; + +static int bm1390_read_temp(struct bm1390_data *data, int *temp) +{ + __be16 temp_raw; + int ret; + + ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp_raw, + sizeof(temp_raw)); + if (ret) + return ret; + + *temp = be16_to_cpu(temp_raw); + + return 0; +} + +static int bm1390_pressure_read(struct bm1390_data *data, u32 *pressure) +{ + /* Pressure data is in 3 8-bit registers */ + u8 raw[3]; + int ret; + + ret = regmap_bulk_read(data->regmap, BM1390_REG_PRESSURE_BASE, + raw, sizeof(raw)); + if (ret < 0) + return ret; + + *pressure = (u32)(raw[2] >> 2 | raw[1] << 6 | raw[0] << 14); + + return 0; +} + + /* The enum values map directly to register bits */ +enum bm1390_meas_mode { + BM1390_MEAS_MODE_STOP = 0x0, + BM1390_MEAS_MODE_1SHOT = 0x1, + BM1390_MEAS_MODE_CONTINUOUS = 0x2, +}; + +static int bm1390_meas_set(struct bm1390_data *data, enum bm1390_meas_mode mode) +{ + return regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_MEAS_MODE, mode); +} + +/* + * If the trigger is not used we just wait until the measurement has + * completed. The data-sheet says maximum measurement cycle (regardless + * the AVE_NUM) is 200 mS so let's just sleep at least that long. If speed + * is needed the trigger should be used. + */ +#define BM1390_MAX_MEAS_TIME_MS 205 + +static int bm1390_read_data(struct bm1390_data *data, + struct iio_chan_spec const *chan, int *val, int *val2) +{ + int ret, warn; + + mutex_lock(&data->mutex); + /* + * We use 'continuous mode' even for raw read because according to the + * data-sheet an one-shot mode can't be used with IIR filter. + */ + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); + if (ret) + goto unlock_out; + + switch (chan->type) { + case IIO_PRESSURE: + msleep(BM1390_MAX_MEAS_TIME_MS); + ret = bm1390_pressure_read(data, val); + break; + case IIO_TEMP: + msleep(BM1390_MAX_MEAS_TIME_MS); + ret = bm1390_read_temp(data, val); + break; + default: + ret = -EINVAL; + } + warn = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); + if (warn) + dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn); +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_read_raw(struct iio_dev *idev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bm1390_data *data = iio_priv(idev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_TEMP) { + *val = 31; + *val2 = 250000; + + return IIO_VAL_INT_PLUS_MICRO; + } else if (chan->type == IIO_PRESSURE) { + /* + * pressure in hPa is register value divided by 2048. + * This means kPa is 1/20480 times the register value, + */ + *val = 1; + *val2 = 2048; + + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(idev); + if (ret) + return ret; + + ret = bm1390_read_data(data, chan, val, val2); + iio_device_release_direct_mode(idev); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int __bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples, + s64 timestamp) +{ + /* BM1390_FIFO_LENGTH is small so we shouldn't run out of stack */ + struct bm1390_data_buf buffer[BM1390_FIFO_LENGTH]; + struct bm1390_data *data = iio_priv(idev); + int smp_lvl, ret, i, warn, dummy; + u64 sample_period; + __be16 temp = 0; + + ret = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &smp_lvl); + if (ret) + return ret; + + smp_lvl = FIELD_GET(BM1390_MASK_FIFO_LVL, smp_lvl); + if (!smp_lvl) + return 0; + + if (smp_lvl > BM1390_FIFO_LENGTH) { + /* + * The fifo holds maximum of 4 samples so valid values + * should be 0, 1, 2, 3, 4 - rest are probably bit errors + * in I2C line. Don't overflow if this happens. + */ + dev_err(data->dev, "bad FIFO level %d\n", smp_lvl); + smp_lvl = BM1390_FIFO_LENGTH; + } + + sample_period = timestamp - data->old_timestamp; + do_div(sample_period, smp_lvl); + + if (samples && smp_lvl > samples) + smp_lvl = samples; + + + /* + * After some testing it appears that the temperature is not readable + * until the FIFO access has been done after the WMI. Thus, we need + * to read the all pressure values to memory and read the temperature + * only after that. + */ + for (i = 0; i < smp_lvl; i++) { + /* + * When we start reading data from the FIFO the sensor goes to + * special FIFO reading mode. If any other register is accessed + * during the FIFO read, samples can be dropped. Prevent access + * until FIFO_LVL is read. We have mutex locked and we do also + * go performing reading of FIFO_LVL even if this read fails. + */ + if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) { + ret = bm1390_pressure_read(data, &buffer[i].pressure); + if (ret) + break; + } + + /* + * Old timestamp is either the previous sample IRQ time, + * previous flush-time or, if this was first sample, the enable + * time. When we add a sample period to that we should get the + * best approximation of the time-stamp we are handling. + * + * Idea is to always keep the "old_timestamp" matching the + * timestamp which we are currently handling. + */ + data->old_timestamp += sample_period; + buffer[i].ts = data->old_timestamp; + } + /* Reading the FIFO_LVL closes the FIFO access sequence */ + warn = regmap_read(data->regmap, BM1390_REG_FIFO_LVL, &dummy); + if (warn) + dev_warn(data->dev, "Closing FIFO sequence failed\n"); + + if (ret) + return ret; + + if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) { + ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, &temp, + sizeof(temp)); + if (ret) + return ret; + } + + if (ret) + return ret; + + for (i = 0; i < smp_lvl; i++) { + buffer[i].temp = temp; + iio_push_to_buffers(idev, &buffer[i]); + } + + return smp_lvl; +} + +static int bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples) +{ + struct bm1390_data *data = iio_priv(idev); + s64 timestamp; + int ret; + + /* + * If fifo_flush is being called from IRQ handler we know the stored + * timestamp is fairly accurate for the last stored sample. If we are + * called as a result of a read operation from userspace and hence + * before the watermark interrupt was triggered, take a timestamp + * now. We can fall anywhere in between two samples so the error in this + * case is at most one sample period. + * We need to have the IRQ disabled or we risk of messing-up + * the timestamps. If we are ran from IRQ, then the + * IRQF_ONESHOT has us covered - but if we are ran by the + * user-space read we need to disable the IRQ to be on a safe + * side. We do this usng synchronous disable so that if the + * IRQ thread is being ran on other CPU we wait for it to be + * finished. + */ + + timestamp = iio_get_time_ns(idev); + mutex_lock(&data->mutex); + ret = __bm1390_fifo_flush(idev, samples, timestamp); + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_set_watermark(struct iio_dev *idev, unsigned int val) +{ + struct bm1390_data *data = iio_priv(idev); + + if (val < BM1390_WMI_MIN || val > BM1390_WMI_MAX) + return -EINVAL; + + mutex_lock(&data->mutex); + data->watermark = val; + mutex_unlock(&data->mutex); + + return 0; +} + +static const struct iio_info bm1390_noirq_info = { + .read_raw = &bm1390_read_raw, +}; + +static const struct iio_info bm1390_info = { + .read_raw = &bm1390_read_raw, + .hwfifo_set_watermark = bm1390_set_watermark, + .hwfifo_flush_to_buffer = bm1390_fifo_flush, +}; + +static int bm1390_chip_init(struct bm1390_data *data) +{ + int ret; + + ret = regmap_write_bits(data->regmap, BM1390_REG_POWER, + BM1390_MASK_POWER, BM1390_POWER_ON); + if (ret) + return ret; + + msleep(1); + + ret = regmap_write_bits(data->regmap, BM1390_REG_RESET, + BM1390_MASK_RESET, BM1390_RESET); + if (ret) + return ret; + + msleep(1); + + ret = regmap_write_bits(data->regmap, BM1390_REG_RESET, + BM1390_MASK_RESET, BM1390_RESET_RELEASE); + if (ret) + return ret; + + msleep(1); + + ret = regmap_reinit_cache(data->regmap, &bm1390_regmap); + if (ret) { + dev_err(data->dev, "Failed to reinit reg cache\n"); + return ret; + } + + /* + * Default to use IIR filter in "middle" mode. Also the AVE_NUM must + * be fixed when IIR is in use. + */ + ret = regmap_update_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_AVE_NUM, BM1390_IIR_AVE_NUM); + if (ret) + return ret; + + return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_IIR_MODE, BM1390_IIR_MODE_MID); +} + +static int bm1390_fifo_set_wmi(struct bm1390_data *data) +{ + u8 regval; + + regval = FIELD_PREP(BM1390_MASK_FIFO_LEN, + data->watermark - BM1390_WMI_MIN); + + return regmap_update_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_FIFO_LEN, regval); +} + +static int bm1390_fifo_enable(struct iio_dev *idev) +{ + struct bm1390_data *data = iio_priv(idev); + int ret; + + /* We can't do buffered stuff without IRQ as we never get WMI */ + if (data->irq <= 0) + return -EINVAL; + + mutex_lock(&data->mutex); + if (data->trigger_enabled) { + ret = -EBUSY; + goto unlock_out; + } + + /* Update watermark to HW */ + ret = bm1390_fifo_set_wmi(data); + if (ret) + goto unlock_out; + + /* Enable WMI_IRQ */ + ret = regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_WMI_EN); + if (ret) + goto unlock_out; + + /* Enable FIFO */ + ret = regmap_set_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_FIFO_EN); + if (ret) + goto unlock_out; + + data->state = BM1390_STATE_FIFO; + + data->old_timestamp = iio_get_time_ns(idev); + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_fifo_disable(struct iio_dev *idev) +{ + struct bm1390_data *data = iio_priv(idev); + int ret; + + msleep(1); + + mutex_lock(&data->mutex); + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); + if (ret) + goto unlock_out; + + /* Disable FIFO */ + ret = regmap_clear_bits(data->regmap, BM1390_REG_FIFO_CTRL, + BM1390_MASK_FIFO_EN); + if (ret) + goto unlock_out; + + data->state = BM1390_STATE_SAMPLE; + + /* Disable WMI_IRQ */ + ret = regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_WMI_EN); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_buffer_postenable(struct iio_dev *idev) +{ + /* + * If we use data-ready trigger, then the IRQ masks should be handled by + * trigger enable and the hardware buffer is not used but we just update + * results to the IIO FIFO when data-ready triggers. + */ + if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED) + return 0; + + return bm1390_fifo_enable(idev); +} + +static int bm1390_buffer_predisable(struct iio_dev *idev) +{ + if (iio_device_get_current_mode(idev) == INDIO_BUFFER_TRIGGERED) + return 0; + + return bm1390_fifo_disable(idev); +} + +static const struct iio_buffer_setup_ops bm1390_buffer_ops = { + .postenable = bm1390_buffer_postenable, + .predisable = bm1390_buffer_predisable, +}; + +static irqreturn_t bm1390_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *idev = pf->indio_dev; + struct bm1390_data *data = iio_priv(idev); + int ret, status; + + /* DRDY is acked by reading status reg */ + ret = regmap_read(data->regmap, BM1390_REG_STATUS, &status); + if (ret || !status) + return IRQ_NONE; + + dev_dbg(data->dev, "DRDY trig status 0x%x\n", status); + + if (test_bit(BM1390_CHAN_PRESSURE, idev->active_scan_mask)) { + ret = bm1390_pressure_read(data, &data->buf.pressure); + if (ret) { + dev_warn(data->dev, "sample read failed %d\n", ret); + return IRQ_NONE; + } + } + + if (test_bit(BM1390_CHAN_TEMP, idev->active_scan_mask)) { + ret = regmap_bulk_read(data->regmap, BM1390_REG_TEMP_HI, + &data->buf.temp, sizeof(data->buf.temp)); + if (ret) { + dev_warn(data->dev, "temp read failed %d\n", ret); + return IRQ_HANDLED; + } + } + + iio_push_to_buffers_with_timestamp(idev, &data->buf, data->timestamp); + iio_trigger_notify_done(idev->trig); + + return IRQ_HANDLED; +} + +/* Get timestamps and wake the thread if we need to read data */ +static irqreturn_t bm1390_irq_handler(int irq, void *private) +{ + struct iio_dev *idev = private; + struct bm1390_data *data = iio_priv(idev); + + data->timestamp = iio_get_time_ns(idev); + + if (data->state == BM1390_STATE_FIFO || data->trigger_enabled) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static irqreturn_t bm1390_irq_thread_handler(int irq, void *private) +{ + struct iio_dev *idev = private; + struct bm1390_data *data = iio_priv(idev); + int ret = IRQ_NONE; + + mutex_lock(&data->mutex); + + if (data->trigger_enabled) { + iio_trigger_poll_nested(data->trig); + ret = IRQ_HANDLED; + } else if (data->state == BM1390_STATE_FIFO) { + int ok; + + ok = __bm1390_fifo_flush(idev, BM1390_FIFO_LENGTH, + data->timestamp); + if (ok > 0) + ret = IRQ_HANDLED; + } + + mutex_unlock(&data->mutex); + + return ret; +} + +static int bm1390_set_drdy_irq(struct bm1390_data *data, bool en) +{ + if (en) + return regmap_set_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_DRDY_EN); + return regmap_clear_bits(data->regmap, BM1390_REG_MODE_CTRL, + BM1390_MASK_DRDY_EN); +} + +static int bm1390_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bm1390_data *data = iio_trigger_get_drvdata(trig); + int ret = 0; + + mutex_lock(&data->mutex); + + if (data->trigger_enabled == state) + goto unlock_out; + + if (data->state == BM1390_STATE_FIFO) { + dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); + ret = -EBUSY; + goto unlock_out; + } + + data->trigger_enabled = state; + + if (state) { + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_CONTINUOUS); + if (ret) + goto unlock_out; + } else { + int dummy; + + ret = bm1390_meas_set(data, BM1390_MEAS_MODE_STOP); + if (ret) + goto unlock_out; + + /* + * We need to read the status register in order to ACK the + * data-ready which may have been generated just before we + * disabled the measurement. + */ + ret = regmap_read(data->regmap, BM1390_REG_STATUS, &dummy); + if (ret) + dev_warn(data->dev, "status read failed\n"); + } + + ret = bm1390_set_drdy_irq(data, state); + +unlock_out: + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_trigger_ops bm1390_trigger_ops = { + .set_trigger_state = bm1390_trigger_set_state, +}; + +static int bm1390_setup_buffer(struct bm1390_data *data, struct iio_dev *idev) +{ + int ret; + + ret = devm_iio_triggered_buffer_setup(data->dev, idev, + &iio_pollfunc_store_time, + &bm1390_trigger_handler, + &bm1390_buffer_ops); + + if (ret) + return dev_err_probe(data->dev, ret, + "iio_triggered_buffer_setup FAIL\n"); + + idev->available_scan_masks = bm1390_scan_masks; + + return 0; +} + +static int bm1390_setup_trigger(struct bm1390_data *data, struct iio_dev *idev, + int irq) +{ + struct iio_trigger *itrig; + char *name; + int ret; + + itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d", idev->name, + iio_device_id(idev)); + if (!itrig) + return -ENOMEM; + + data->trig = itrig; + + itrig->ops = &bm1390_trigger_ops; + iio_trigger_set_drvdata(itrig, data); + + name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bm1390", + dev_name(data->dev)); + if (name == NULL) + return -ENOMEM; + + ret = devm_request_threaded_irq(data->dev, irq, bm1390_irq_handler, + &bm1390_irq_thread_handler, + IRQF_ONESHOT, name, idev); + if (ret) + return dev_err_probe(data->dev, ret, "Could not request IRQ\n"); + + + ret = devm_iio_trigger_register(data->dev, itrig); + if (ret) + return dev_err_probe(data->dev, ret, + "Trigger registration failed\n"); + + return 0; +} + +static int bm1390_probe(struct i2c_client *i2c) +{ + struct bm1390_data *data; + struct regmap *regmap; + struct iio_dev *idev; + struct device *dev; + unsigned int part_id; + int ret; + + dev = &i2c->dev; + + regmap = devm_regmap_init_i2c(i2c, &bm1390_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialize Regmap\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulator\n"); + + ret = regmap_read(regmap, BM1390_REG_PART_ID, &part_id); + if (ret) + return dev_err_probe(dev, ret, "Failed to access sensor\n"); + + if (part_id != BM1390_ID) + dev_warn(dev, "unknown device 0x%x\n", part_id); + + idev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!idev) + return -ENOMEM; + + data = iio_priv(idev); + data->regmap = regmap; + data->dev = dev; + data->irq = i2c->irq; + /* + * For now we just allow BM1390_WMI_MIN to BM1390_WMI_MAX and + * discard every other configuration when triggered mode is not used. + */ + data->watermark = BM1390_WMI_MAX; + mutex_init(&data->mutex); + + idev->channels = bm1390_channels; + idev->num_channels = ARRAY_SIZE(bm1390_channels); + idev->name = "bm1390"; + idev->modes = INDIO_DIRECT_MODE; + + ret = bm1390_chip_init(data); + if (ret) + return dev_err_probe(dev, ret, "sensor init failed\n"); + + ret = bm1390_setup_buffer(data, idev); + if (ret) + return ret; + + /* No trigger if we don't have IRQ for data-ready and WMI */ + if (i2c->irq > 0) { + idev->info = &bm1390_info; + idev->modes |= INDIO_BUFFER_SOFTWARE; + ret = bm1390_setup_trigger(data, idev, i2c->irq); + if (ret) + return ret; + } else { + idev->info = &bm1390_noirq_info; + } + + ret = devm_iio_device_register(dev, idev); + if (ret < 0) + return dev_err_probe(dev, ret, + "Unable to register iio device\n"); + + return 0; +} + +static const struct of_device_id bm1390_of_match[] = { + { .compatible = "rohm,bm1390glv-z" }, + {} +}; +MODULE_DEVICE_TABLE(of, bm1390_of_match); + +static const struct i2c_device_id bm1390_id[] = { + { "bm1390glv-z", }, + {} +}; +MODULE_DEVICE_TABLE(i2c, bm1390_id); + +static struct i2c_driver bm1390_driver = { + .driver = { + .name = "bm1390", + .of_match_table = bm1390_of_match, + /* + * Probing explicitly requires a few millisecond of sleep. + * Enabling the VDD regulator may include ramp up rates. + */ + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = bm1390_probe, + .id_table = bm1390_id, +}; +module_i2c_driver(bm1390_driver); + +MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); +MODULE_DESCRIPTION("Driver for ROHM BM1390 pressure sensor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c index 571ea1812246..4df506bb8b38 100644 --- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -239,15 +239,13 @@ static int cros_ec_mkbp_proximity_probe(struct platform_device *pdev) return 0; } -static int cros_ec_mkbp_proximity_remove(struct platform_device *pdev) +static void cros_ec_mkbp_proximity_remove(struct platform_device *pdev) { struct cros_ec_mkbp_proximity_data *data = platform_get_drvdata(pdev); struct cros_ec_device *ec = data->ec; blocking_notifier_chain_unregister(&ec->event_notifier, &data->notifier); - - return 0; } static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = { @@ -263,7 +261,7 @@ static struct platform_driver cros_ec_mkbp_proximity_driver = { .pm = pm_sleep_ptr(&cros_ec_mkbp_proximity_pm_ops), }, .probe = cros_ec_mkbp_proximity_probe, - .remove = cros_ec_mkbp_proximity_remove, + .remove_new = cros_ec_mkbp_proximity_remove, }; module_platform_driver(cros_ec_mkbp_proximity_driver); diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index faf2f806ce80..86c57672fc7e 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -344,7 +344,7 @@ static int srf04_probe(struct platform_device *pdev) return ret; } -static int srf04_remove(struct platform_device *pdev) +static void srf04_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct srf04_data *data = iio_priv(indio_dev); @@ -355,8 +355,6 @@ static int srf04_remove(struct platform_device *pdev) pm_runtime_disable(data->dev); pm_runtime_set_suspended(data->dev); } - - return 0; } static int srf04_pm_runtime_suspend(struct device *dev) @@ -391,7 +389,7 @@ static const struct dev_pm_ops srf04_pm_ops = { static struct platform_driver srf04_driver = { .probe = srf04_probe, - .remove = srf04_remove, + .remove_new = srf04_remove, .driver = { .name = "srf04-gpio", .of_match_table = of_srf04_match, diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index d977aacb7491..0d230a0dff56 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -159,6 +159,11 @@ static_assert(SX9310_NUM_CHANNELS <= SX_COMMON_MAX_NUM_CHANNELS); } #define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL) +struct sx931x_info { + const char *name; + unsigned int whoami; +}; + static const struct iio_chan_spec sx9310_channels[] = { SX9310_CHANNEL(0), /* CS0 */ SX9310_CHANNEL(1), /* CS1 */ @@ -902,7 +907,7 @@ static int sx9310_check_whoami(struct device *dev, struct iio_dev *indio_dev) { struct sx_common_data *data = iio_priv(indio_dev); - unsigned int long ddata; + const struct sx931x_info *ddata; unsigned int whoami; int ret; @@ -910,20 +915,11 @@ static int sx9310_check_whoami(struct device *dev, if (ret) return ret; - ddata = (uintptr_t)device_get_match_data(dev); - if (ddata != whoami) - return -EINVAL; - - switch (whoami) { - case SX9310_WHOAMI_VALUE: - indio_dev->name = "sx9310"; - break; - case SX9311_WHOAMI_VALUE: - indio_dev->name = "sx9311"; - break; - default: + ddata = device_get_match_data(dev); + if (ddata->whoami != whoami) return -ENODEV; - } + + indio_dev->name = ddata->name; return 0; } @@ -1015,23 +1011,33 @@ out: static DEFINE_SIMPLE_DEV_PM_OPS(sx9310_pm_ops, sx9310_suspend, sx9310_resume); +static const struct sx931x_info sx9310_info = { + .name = "sx9310", + .whoami = SX9310_WHOAMI_VALUE, +}; + +static const struct sx931x_info sx9311_info = { + .name = "sx9311", + .whoami = SX9311_WHOAMI_VALUE, +}; + static const struct acpi_device_id sx9310_acpi_match[] = { - { "STH9310", SX9310_WHOAMI_VALUE }, - { "STH9311", SX9311_WHOAMI_VALUE }, + { "STH9310", (kernel_ulong_t)&sx9310_info }, + { "STH9311", (kernel_ulong_t)&sx9311_info }, {} }; MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match); static const struct of_device_id sx9310_of_match[] = { - { .compatible = "semtech,sx9310", (void *)SX9310_WHOAMI_VALUE }, - { .compatible = "semtech,sx9311", (void *)SX9311_WHOAMI_VALUE }, + { .compatible = "semtech,sx9310", &sx9310_info }, + { .compatible = "semtech,sx9311", &sx9311_info }, {} }; MODULE_DEVICE_TABLE(of, sx9310_of_match); static const struct i2c_device_id sx9310_id[] = { - { "sx9310", SX9310_WHOAMI_VALUE }, - { "sx9311", SX9311_WHOAMI_VALUE }, + { "sx9310", (kernel_ulong_t)&sx9310_info }, + { "sx9311", (kernel_ulong_t)&sx9311_info }, {} }; MODULE_DEVICE_TABLE(i2c, sx9310_id); diff --git a/drivers/iio/resolver/Kconfig b/drivers/iio/resolver/Kconfig index 47dbfead9b31..424529d36080 100644 --- a/drivers/iio/resolver/Kconfig +++ b/drivers/iio/resolver/Kconfig @@ -25,4 +25,17 @@ config AD2S1200 To compile this driver as a module, choose M here: the module will be called ad2s1200. + +config AD2S1210 + tristate "Analog Devices ad2s1210 driver" + depends on SPI + depends on COMMON_CLK + depends on GPIOLIB || COMPILE_TEST + help + Say yes here to build support for Analog Devices spi resolver + to digital converters, ad2s1210, provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad2s1210. + endmenu diff --git a/drivers/iio/resolver/Makefile b/drivers/iio/resolver/Makefile index fa558138ce45..7f6c876c35ae 100644 --- a/drivers/iio/resolver/Makefile +++ b/drivers/iio/resolver/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_AD2S90) += ad2s90.o obj-$(CONFIG_AD2S1200) += ad2s1200.o +obj-$(CONFIG_AD2S1210) += ad2s1210.o diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c new file mode 100644 index 000000000000..1bd1b950e7cc --- /dev/null +++ b/drivers/iio/resolver/ad2s1210.c @@ -0,0 +1,1519 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210 + * + * Copyright (c) 2010-2010 Analog Devices Inc. + * Copyright (c) 2023 BayLibre, SAS + * + * Device register to IIO ABI mapping: + * + * Register | Addr | IIO ABI (sysfs) + * ----------------------------|------|------------------------------------------- + * DOS Overrange Threshold | 0x89 | events/in_altvoltage0_thresh_rising_value + * DOS Mismatch Threshold | 0x8A | events/in_altvoltage0_mag_rising_value + * DOS Reset Maximum Threshold | 0x8B | events/in_altvoltage0_mag_rising_reset_max + * DOS Reset Minimum Threshold | 0x8C | events/in_altvoltage0_mag_rising_reset_min + * LOT High Threshold | 0x8D | events/in_angl1_thresh_rising_value + * LOT Low Threshold [1] | 0x8E | events/in_angl1_thresh_rising_hysteresis + * Excitation Frequency | 0x91 | out_altvoltage0_frequency + * Control | 0x92 | *as bit fields* + * Phase lock range | D5 | events/in_phase0_mag_rising_value + * Hysteresis | D4 | in_angl0_hysteresis + * Encoder resolution | D3:2 | *not implemented* + * Resolution | D1:0 | *device tree: assigned-resolution-bits* + * Soft Reset | 0xF0 | [2] + * Fault | 0xFF | *not implemented* + * + * [1]: The value written to the LOT low register is high value minus the + * hysteresis. + * [2]: Soft reset is performed when `out_altvoltage0_frequency` is written. + * + * Fault to event mapping: + * + * Fault | | Channel | Type | Direction + * ----------------------------------------|----|--------------------------------- + * Sine/cosine inputs clipped [3] | D7 | altvoltage1 | mag | either + * Sine/cosine inputs below LOS | D6 | altvoltage0 | thresh | falling + * Sine/cosine inputs exceed DOS overrange | D5 | altvoltage0 | thresh | rising + * Sine/cosine inputs exceed DOS mismatch | D4 | altvoltage0 | mag | rising + * Tracking error exceeds LOT | D3 | angl1 | thresh | rising + * Velocity exceeds maximum tracking rate | D2 | anglvel0 | mag | rising + * Phase error exceeds phase lock range | D1 | phase0 | mag | rising + * Configuration parity error | D0 | *writes to kernel log* + * + * [3]: The chip does not differentiate between fault on sine vs. cosine so + * there will also be an event on the altvoltage2 channel. + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> +#include <linux/types.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +/* control register flags */ +#define AD2S1210_ADDRESS_DATA BIT(7) +#define AD2S1210_PHASE_LOCK_RANGE_44 BIT(5) +#define AD2S1210_ENABLE_HYSTERESIS BIT(4) +#define AD2S1210_SET_ENRES GENMASK(3, 2) +#define AD2S1210_SET_RES GENMASK(1, 0) + +/* fault register flags */ +#define AD2S1210_FAULT_CLIP BIT(7) +#define AD2S1210_FAULT_LOS BIT(6) +#define AD2S1210_FAULT_DOS_OVR BIT(5) +#define AD2S1210_FAULT_DOS_MIS BIT(4) +#define AD2S1210_FAULT_LOT BIT(3) +#define AD2S1210_FAULT_VELOCITY BIT(2) +#define AD2S1210_FAULT_PHASE BIT(1) +#define AD2S1210_FAULT_CONFIG_PARITY BIT(0) + +#define AD2S1210_REG_POSITION_MSB 0x80 +#define AD2S1210_REG_POSITION_LSB 0x81 +#define AD2S1210_REG_VELOCITY_MSB 0x82 +#define AD2S1210_REG_VELOCITY_LSB 0x83 +#define AD2S1210_REG_LOS_THRD 0x88 +#define AD2S1210_REG_DOS_OVR_THRD 0x89 +#define AD2S1210_REG_DOS_MIS_THRD 0x8A +#define AD2S1210_REG_DOS_RST_MAX_THRD 0x8B +#define AD2S1210_REG_DOS_RST_MIN_THRD 0x8C +#define AD2S1210_REG_LOT_HIGH_THRD 0x8D +#define AD2S1210_REG_LOT_LOW_THRD 0x8E +#define AD2S1210_REG_EXCIT_FREQ 0x91 +#define AD2S1210_REG_CONTROL 0x92 +#define AD2S1210_REG_SOFT_RESET 0xF0 +#define AD2S1210_REG_FAULT 0xFF + +#define AD2S1210_MIN_CLKIN 6144000 +#define AD2S1210_MAX_CLKIN 10240000 +#define AD2S1210_MIN_EXCIT 2000 +#define AD2S1210_DEF_EXCIT 10000 +#define AD2S1210_MAX_EXCIT 20000 +#define AD2S1210_MIN_FCW 0x4 +#define AD2S1210_MAX_FCW 0x50 + +/* 44 degrees ~= 0.767945 radians */ +#define PHASE_44_DEG_TO_RAD_INT 0 +#define PHASE_44_DEG_TO_RAD_MICRO 767945 +/* 360 degrees ~= 6.283185 radians */ +#define PHASE_360_DEG_TO_RAD_INT 6 +#define PHASE_360_DEG_TO_RAD_MICRO 283185 + +/* Threshold voltage registers have 1 LSB == 38 mV */ +#define THRESHOLD_MILLIVOLT_PER_LSB 38 +/* max voltage for threshold registers is 0x7F * 38 mV */ +#define THRESHOLD_RANGE_STR "[0 38 4826]" + +#define FAULT_ONESHOT(bit, new, old) (new & bit && !(old & bit)) + +enum ad2s1210_mode { + MOD_POS = 0b00, + MOD_VEL = 0b01, + MOD_RESERVED = 0b10, + MOD_CONFIG = 0b11, +}; + +enum ad2s1210_resolution { + AD2S1210_RES_10 = 0b00, + AD2S1210_RES_12 = 0b01, + AD2S1210_RES_14 = 0b10, + AD2S1210_RES_16 = 0b11, +}; + +struct ad2s1210_state { + struct mutex lock; + struct spi_device *sdev; + /** GPIO pin connected to SAMPLE line. */ + struct gpio_desc *sample_gpio; + /** GPIO pins connected to A0 and A1 lines. */ + struct gpio_descs *mode_gpios; + /** Used to access config registers. */ + struct regmap *regmap; + /** The external oscillator frequency in Hz. */ + unsigned long clkin_hz; + /** Available raw hysteresis values based on resolution. */ + int hysteresis_available[2]; + /** The selected resolution */ + enum ad2s1210_resolution resolution; + /** Copy of fault register from the previous read. */ + u8 prev_fault_flags; + /** For reading raw sample value via SPI. */ + struct { + __be16 raw; + u8 fault; + } sample __aligned(IIO_DMA_MINALIGN); + /** Scan buffer */ + struct { + __be16 chan[2]; + /* Ensure timestamp is naturally aligned. */ + s64 timestamp __aligned(8); + } scan; + /** SPI transmit buffer. */ + u8 rx[2]; + /** SPI receive buffer. */ + u8 tx[2]; +}; + +static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode mode) +{ + struct gpio_descs *gpios = st->mode_gpios; + DECLARE_BITMAP(bitmap, 2); + + bitmap[0] = mode; + + return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info, + bitmap); +} + +/* + * Writes the given data to the given register address. + * + * If the mode is configurable, the device will first be placed in + * configuration mode. + */ +static int ad2s1210_regmap_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct ad2s1210_state *st = context; + struct spi_transfer xfers[] = { + { + .len = 1, + .rx_buf = &st->rx[0], + .tx_buf = &st->tx[0], + .cs_change = 1, + }, { + .len = 1, + .rx_buf = &st->rx[1], + .tx_buf = &st->tx[1], + }, + }; + int ret; + + /* values can only be 7 bits, the MSB indicates an address */ + if (val & ~0x7F) + return -EINVAL; + + st->tx[0] = reg; + st->tx[1] = val; + + ret = ad2s1210_set_mode(st, MOD_CONFIG); + if (ret < 0) + return ret; + + ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); + if (ret < 0) + return ret; + + /* soft reset also clears the fault register */ + if (reg == AD2S1210_REG_SOFT_RESET) + st->prev_fault_flags = 0; + + return 0; +} + +/* + * Reads value from one of the registers. + * + * If the mode is configurable, the device will first be placed in + * configuration mode. + */ +static int ad2s1210_regmap_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct ad2s1210_state *st = context; + struct spi_transfer xfers[] = { + { + .len = 1, + .rx_buf = &st->rx[0], + .tx_buf = &st->tx[0], + .cs_change = 1, + }, { + .len = 1, + .rx_buf = &st->rx[1], + .tx_buf = &st->tx[1], + }, + }; + int ret; + + ret = ad2s1210_set_mode(st, MOD_CONFIG); + if (ret < 0) + return ret; + + st->tx[0] = reg; + /* + * Must be valid register address here otherwise this could write data. + * It doesn't matter which one as long as reading doesn't have side- + * effects. + */ + st->tx[1] = AD2S1210_REG_CONTROL; + + ret = spi_sync_transfer(st->sdev, xfers, ARRAY_SIZE(xfers)); + if (ret < 0) + return ret; + + /* reading the fault register also clears it */ + if (reg == AD2S1210_REG_FAULT) + st->prev_fault_flags = 0; + + /* + * If the D7 bit is set on any read/write register, it indicates a + * parity error. The fault register is read-only and the D7 bit means + * something else there. + */ + if (reg != AD2S1210_REG_FAULT && st->rx[1] & AD2S1210_ADDRESS_DATA) + return -EBADMSG; + + *val = st->rx[1]; + + return 0; +} + +/* + * Toggles the SAMPLE line on the AD2S1210 to latch in the current position, + * velocity, and faults. + * + * Must be called with lock held. + */ +static void ad2s1210_toggle_sample_line(struct ad2s1210_state *st) +{ + /* + * Datasheet specifies minimum hold time t16 = 2 * tck + 20 ns. So the + * longest time needed is when CLKIN is 6.144 MHz, in which case t16 + * ~= 350 ns. The same delay is also needed before re-asserting the + * SAMPLE line. + */ + gpiod_set_value(st->sample_gpio, 1); + ndelay(350); + gpiod_set_value(st->sample_gpio, 0); + ndelay(350); +} + +/* + * Sets the excitation frequency and performs software reset. + * + * Must be called with lock held. + */ +static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st, + u16 fexcit) +{ + /* Map resolution to settle time in milliseconds. */ + static const int track_time_ms[] = { 10, 20, 25, 60 }; + unsigned int ignored; + int ret; + u8 fcw; + + fcw = fexcit * (1 << 15) / st->clkin_hz; + if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) + return -ERANGE; + + ret = regmap_write(st->regmap, AD2S1210_REG_EXCIT_FREQ, fcw); + if (ret < 0) + return ret; + + /* + * Software reset reinitializes the excitation frequency output. + * It does not reset any of the configuration registers. + */ + ret = regmap_write(st->regmap, AD2S1210_REG_SOFT_RESET, 0); + if (ret < 0) + return ret; + + /* + * Soft reset always triggers some faults due the change in the output + * signal so clear the faults too. We need to delay for some time + * (what datasheet calls t[track]) to allow things to settle before + * clearing the faults. + */ + msleep(track_time_ms[st->resolution] * 8192000 / st->clkin_hz); + + /* Reading the fault register clears the faults. */ + ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &ignored); + if (ret < 0) + return ret; + + /* Have to toggle sample line to get fault output pins to reset. */ + ad2s1210_toggle_sample_line(st); + + return 0; +} + +static void ad2s1210_push_events(struct iio_dev *indio_dev, + u8 flags, s64 timestamp) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + /* Sine/cosine inputs clipped */ + if (FAULT_ONESHOT(AD2S1210_FAULT_CLIP, flags, st->prev_fault_flags)) { + /* + * The chip does not differentiate between fault on sine vs. + * cosine channel so we just send an event on both channels. + */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 1, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_EITHER), + timestamp); + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 2, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_EITHER), + timestamp); + } + + /* Sine/cosine inputs below LOS threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_LOS, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + timestamp); + + /* Sine/cosine inputs exceed DOS overrange threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_OVR, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + + /* Sine/cosine inputs exceed DOS mismatch threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_DOS_MIS, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ALTVOLTAGE, 0, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + timestamp); + + /* Tracking error exceeds LOT threshold */ + if (FAULT_ONESHOT(AD2S1210_FAULT_LOT, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ANGL, 1, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + + /* Velocity exceeds maximum tracking rate */ + if (FAULT_ONESHOT(AD2S1210_FAULT_VELOCITY, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_ANGL_VEL, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + timestamp); + + /* Phase error exceeds phase lock range */ + if (FAULT_ONESHOT(AD2S1210_FAULT_PHASE, flags, st->prev_fault_flags)) + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PHASE, 0, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + timestamp); + + /* Configuration parity error */ + if (FAULT_ONESHOT(AD2S1210_FAULT_CONFIG_PARITY, flags, + st->prev_fault_flags)) + /* + * Userspace should also get notified of this via error return + * when trying to write to any attribute that writes a register. + */ + dev_err_ratelimited(&indio_dev->dev, + "Configuration parity error\n"); + + st->prev_fault_flags = flags; +} + +static int ad2s1210_single_conversion(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + s64 timestamp; + int ret; + + guard(mutex)(&st->lock); + + ad2s1210_toggle_sample_line(st); + timestamp = iio_get_time_ns(indio_dev); + + switch (chan->type) { + case IIO_ANGL: + ret = ad2s1210_set_mode(st, MOD_POS); + break; + case IIO_ANGL_VEL: + ret = ad2s1210_set_mode(st, MOD_VEL); + break; + default: + return -EINVAL; + } + if (ret < 0) + return ret; + ret = spi_read(st->sdev, &st->sample, 3); + if (ret < 0) + return ret; + + switch (chan->type) { + case IIO_ANGL: + *val = be16_to_cpu(st->sample.raw); + ret = IIO_VAL_INT; + break; + case IIO_ANGL_VEL: + *val = (s16)be16_to_cpu(st->sample.raw); + ret = IIO_VAL_INT; + break; + default: + return -EINVAL; + } + + ad2s1210_push_events(indio_dev, st->sample.fault, timestamp); + + return ret; +} + +static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val) +{ + int ret; + + guard(mutex)(&st->lock); + ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_ENABLE_HYSTERESIS); + if (ret < 0) + return ret; + + *val = ret << (2 * (AD2S1210_RES_16 - st->resolution)); + return IIO_VAL_INT; +} + +static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val) +{ + guard(mutex)(&st->lock); + return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_ENABLE_HYSTERESIS, + val ? AD2S1210_ENABLE_HYSTERESIS : 0); +} + +static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st, + int *val, int *val2) +{ + int ret; + + guard(mutex)(&st->lock); + ret = regmap_test_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44); + if (ret < 0) + return ret; + + if (ret) { + /* 44 degrees as radians */ + *val = PHASE_44_DEG_TO_RAD_INT; + *val2 = PHASE_44_DEG_TO_RAD_MICRO; + } else { + /* 360 degrees as radians */ + *val = PHASE_360_DEG_TO_RAD_INT; + *val2 = PHASE_360_DEG_TO_RAD_MICRO; + } + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st, + int val, int val2) +{ + int deg; + + /* convert radians to degrees - only two allowable values */ + if (val == PHASE_44_DEG_TO_RAD_INT && val2 == PHASE_44_DEG_TO_RAD_MICRO) + deg = 44; + else if (val == PHASE_360_DEG_TO_RAD_INT && + val2 == PHASE_360_DEG_TO_RAD_MICRO) + deg = 360; + else + return -EINVAL; + + guard(mutex)(&st->lock); + return regmap_update_bits(st->regmap, AD2S1210_REG_CONTROL, + AD2S1210_PHASE_LOCK_RANGE_44, + deg == 44 ? AD2S1210_PHASE_LOCK_RANGE_44 : 0); +} + +/* map resolution to microradians/LSB for LOT registers */ +static const int ad2s1210_lot_threshold_urad_per_lsb[] = { + 6184, /* 10-bit: ~0.35 deg/LSB, 45 deg max */ + 2473, /* 12-bit: ~0.14 deg/LSB, 18 deg max */ + 1237, /* 14-bit: ~0.07 deg/LSB, 9 deg max */ + 1237, /* 16-bit: same as 14-bit */ +}; + +static int ad2s1210_get_voltage_threshold(struct ad2s1210_state *st, + unsigned int reg, int *val) +{ + unsigned int reg_val; + int ret; + + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, reg, ®_val); + if (ret < 0) + return ret; + + *val = reg_val * THRESHOLD_MILLIVOLT_PER_LSB; + return IIO_VAL_INT; +} + +static int ad2s1210_set_voltage_threshold(struct ad2s1210_state *st, + unsigned int reg, int val) +{ + unsigned int reg_val; + + reg_val = val / THRESHOLD_MILLIVOLT_PER_LSB; + + guard(mutex)(&st->lock); + return regmap_write(st->regmap, reg, reg_val); +} + +static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st, + int *val, int *val2) +{ + unsigned int reg_val; + int ret; + + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, ®_val); + if (ret < 0) + return ret; + + *val = 0; + *val2 = reg_val * ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st, + int val, int val2) +{ + unsigned int high_reg_val, low_reg_val, hysteresis; + int ret; + + /* all valid values are between 0 and pi/4 radians */ + if (val != 0) + return -EINVAL; + + guard(mutex)(&st->lock); + /* + * We need to read both high and low registers first so we can preserve + * the hysteresis. + */ + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); + if (ret < 0) + return ret; + + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); + if (ret < 0) + return ret; + + hysteresis = high_reg_val - low_reg_val; + high_reg_val = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + low_reg_val = high_reg_val - hysteresis; + + ret = regmap_write(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, high_reg_val); + if (ret < 0) + return ret; + + return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, low_reg_val); +} + +static int ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st, + int *val, int *val2) +{ + unsigned int high_reg_val, low_reg_val; + int ret; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, &high_reg_val); + if (ret < 0) + return ret; + + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_LOW_THRD, &low_reg_val); + if (ret < 0) + return ret; + + /* sysfs value is hysteresis rather than actual low value */ + *val = 0; + *val2 = (high_reg_val - low_reg_val) * + ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad2s1210_set_lot_low_threshold(struct ad2s1210_state *st, + int val, int val2) +{ + unsigned int reg_val, hysteresis; + int ret; + + /* all valid values are between 0 and pi/4 radians */ + if (val != 0) + return -EINVAL; + + hysteresis = val2 / ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, AD2S1210_REG_LOT_HIGH_THRD, ®_val); + if (ret < 0) + return ret; + + return regmap_write(st->regmap, AD2S1210_REG_LOT_LOW_THRD, + reg_val - hysteresis); +} + +static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val) +{ + unsigned int reg_val; + int ret; + + guard(mutex)(&st->lock); + + ret = regmap_read(st->regmap, AD2S1210_REG_EXCIT_FREQ, ®_val); + if (ret < 0) + return ret; + + *val = reg_val * st->clkin_hz / (1 << 15); + return IIO_VAL_INT; +} + +static int ad2s1210_set_excitation_frequency(struct ad2s1210_state *st, int val) +{ + if (val < AD2S1210_MIN_EXCIT || val > AD2S1210_MAX_EXCIT) + return -EINVAL; + + guard(mutex)(&st->lock); + return ad2s1210_reinit_excitation_frequency(st, val); +} + +static const int ad2s1210_velocity_scale[] = { + 17089132, /* 8.192MHz / (2*pi * 2500 / 2^15) */ + 42722830, /* 8.192MHz / (2*pi * 1000 / 2^15) */ + 85445659, /* 8.192MHz / (2*pi * 500 / 2^15) */ + 341782638, /* 8.192MHz / (2*pi * 125 / 2^15) */ +}; + +static int ad2s1210_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return ad2s1210_single_conversion(indio_dev, chan, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL: + /* approx 0.3 arc min converted to radians */ + *val = 0; + *val2 = 95874; + return IIO_VAL_INT_PLUS_NANO; + case IIO_ANGL_VEL: + *val = st->clkin_hz; + *val2 = ad2s1210_velocity_scale[st->resolution]; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_FREQUENCY: + switch (chan->type) { + case IIO_ALTVOLTAGE: + return ad2s1210_get_excitation_frequency(st, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + return ad2s1210_get_hysteresis(st, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad2s1210_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, + int *length, long mask) +{ + static const int excitation_frequency_available[] = { + AD2S1210_MIN_EXCIT, + 250, /* step */ + AD2S1210_MAX_EXCIT, + }; + + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + switch (chan->type) { + case IIO_ALTVOLTAGE: + *type = IIO_VAL_INT; + *vals = excitation_frequency_available; + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + *vals = st->hysteresis_available; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(st->hysteresis_available); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad2s1210_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_FREQUENCY: + switch (chan->type) { + case IIO_ALTVOLTAGE: + return ad2s1210_set_excitation_frequency(st, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_HYSTERESIS: + switch (chan->type) { + case IIO_ANGL: + return ad2s1210_set_hysteresis(st, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static const struct iio_event_spec ad2s1210_position_event_spec[] = { + { + /* Tracking error exceeds LOT threshold fault. */ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = + /* Loss of tracking high threshold. */ + BIT(IIO_EV_INFO_VALUE) | + /* Loss of tracking low threshold. */ + BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + +static const struct iio_event_spec ad2s1210_velocity_event_spec[] = { + { + /* Velocity exceeds maximum tracking rate fault. */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + }, +}; + +static const struct iio_event_spec ad2s1210_phase_event_spec[] = { + { + /* Phase error fault. */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + /* Phase lock range. */ + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, +}; + +static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] = { + { + /* Sine/cosine below LOS threshold fault. */ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + /* Loss of signal threshold. */ + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, + { + /* Sine/cosine DOS overrange fault.*/ + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + /* Degredation of signal overrange threshold. */ + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, + { + /* Sine/cosine DOS mismatch fault.*/ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, +}; + +static const struct iio_event_spec ad2s1210_sin_cos_event_spec[] = { + { + /* Sine/cosine clipping fault. */ + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_EITHER, + }, +}; + +static const struct iio_chan_spec ad2s1210_channels[] = { + { + .type = IIO_ANGL, + .indexed = 1, + .channel = 0, + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_HYSTERESIS), + }, { + .type = IIO_ANGL_VEL, + .indexed = 1, + .channel = 0, + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .event_spec = ad2s1210_velocity_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_velocity_event_spec), + }, + IIO_CHAN_SOFT_TIMESTAMP(2), + { + /* used to configure LOT thresholds and get tracking error */ + .type = IIO_ANGL, + .indexed = 1, + .channel = 1, + .scan_index = -1, + .event_spec = ad2s1210_position_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_position_event_spec), + }, + { + /* used to configure phase lock range and get phase lock error */ + .type = IIO_PHASE, + .indexed = 1, + .channel = 0, + .scan_index = -1, + .event_spec = ad2s1210_phase_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_phase_event_spec), + }, { + /* excitation frequency output */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 0, + .output = 1, + .scan_index = -1, + .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY), + .info_mask_separate_available = BIT(IIO_CHAN_INFO_FREQUENCY), + }, { + /* monitor signal */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 0, + .scan_index = -1, + .event_spec = ad2s1210_monitor_signal_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_monitor_signal_event_spec), + }, { + /* sine input */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 1, + .scan_index = -1, + .event_spec = ad2s1210_sin_cos_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec), + }, { + /* cosine input */ + .type = IIO_ALTVOLTAGE, + .indexed = 1, + .channel = 2, + .scan_index = -1, + .event_spec = ad2s1210_sin_cos_event_spec, + .num_event_specs = ARRAY_SIZE(ad2s1210_sin_cos_event_spec), + }, +}; + +static ssize_t event_attr_voltage_reg_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + struct iio_dev_attr *iattr = to_iio_dev_attr(attr); + unsigned int value; + int ret; + + guard(mutex)(&st->lock); + ret = regmap_read(st->regmap, iattr->address, &value); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", value * THRESHOLD_MILLIVOLT_PER_LSB); +} + +static ssize_t event_attr_voltage_reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + struct iio_dev_attr *iattr = to_iio_dev_attr(attr); + u16 data; + int ret; + + ret = kstrtou16(buf, 10, &data); + if (ret) + return -EINVAL; + + guard(mutex)(&st->lock); + ret = regmap_write(st->regmap, iattr->address, + data / THRESHOLD_MILLIVOLT_PER_LSB); + if (ret < 0) + return ret; + + return len; +} + +static ssize_t +in_angl1_thresh_rising_value_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + + return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F); +} + +static ssize_t +in_angl1_thresh_rising_hysteresis_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); + int step = ad2s1210_lot_threshold_urad_per_lsb[st->resolution]; + + return sysfs_emit(buf, "[0 0.%06d 0.%06d]\n", step, step * 0x7F); +} + +static IIO_CONST_ATTR(in_phase0_mag_rising_value_available, + __stringify(PHASE_44_DEG_TO_RAD_INT) "." + __stringify(PHASE_44_DEG_TO_RAD_MICRO) " " + __stringify(PHASE_360_DEG_TO_RAD_INT) "." + __stringify(PHASE_360_DEG_TO_RAD_MICRO)); +static IIO_CONST_ATTR(in_altvoltage0_thresh_falling_value_available, + THRESHOLD_RANGE_STR); +static IIO_CONST_ATTR(in_altvoltage0_thresh_rising_value_available, + THRESHOLD_RANGE_STR); +static IIO_CONST_ATTR(in_altvoltage0_mag_rising_value_available, + THRESHOLD_RANGE_STR); +static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_max, 0644, + event_attr_voltage_reg_show, event_attr_voltage_reg_store, + AD2S1210_REG_DOS_RST_MAX_THRD); +static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_max_available, THRESHOLD_RANGE_STR); +static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_min, 0644, + event_attr_voltage_reg_show, event_attr_voltage_reg_store, + AD2S1210_REG_DOS_RST_MIN_THRD); +static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_min_available, THRESHOLD_RANGE_STR); +static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0); +static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0); + +static struct attribute *ad2s1210_event_attributes[] = { + &iio_const_attr_in_phase0_mag_rising_value_available.dev_attr.attr, + &iio_const_attr_in_altvoltage0_thresh_falling_value_available.dev_attr.attr, + &iio_const_attr_in_altvoltage0_thresh_rising_value_available.dev_attr.attr, + &iio_const_attr_in_altvoltage0_mag_rising_value_available.dev_attr.attr, + &iio_dev_attr_in_altvoltage0_mag_rising_reset_max.dev_attr.attr, + &iio_const_attr_in_altvoltage0_mag_rising_reset_max_available.dev_attr.attr, + &iio_dev_attr_in_altvoltage0_mag_rising_reset_min.dev_attr.attr, + &iio_const_attr_in_altvoltage0_mag_rising_reset_min_available.dev_attr.attr, + &iio_dev_attr_in_angl1_thresh_rising_value_available.dev_attr.attr, + &iio_dev_attr_in_angl1_thresh_rising_hysteresis_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad2s1210_event_attribute_group = { + .attrs = ad2s1210_event_attributes, +}; + +static int ad2s1210_initial(struct ad2s1210_state *st) +{ + unsigned int data; + int ret; + + guard(mutex)(&st->lock); + + /* Use default config register value plus resolution from devicetree. */ + data = FIELD_PREP(AD2S1210_PHASE_LOCK_RANGE_44, 1); + data |= FIELD_PREP(AD2S1210_ENABLE_HYSTERESIS, 1); + data |= FIELD_PREP(AD2S1210_SET_ENRES, 0x3); + data |= FIELD_PREP(AD2S1210_SET_RES, st->resolution); + + ret = regmap_write(st->regmap, AD2S1210_REG_CONTROL, data); + if (ret < 0) + return ret; + + return ad2s1210_reinit_excitation_frequency(st, AD2S1210_DEF_EXCIT); +} + +static int ad2s1210_read_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + char *label) +{ + if (chan->type == IIO_ANGL) { + if (chan->channel == 0) + return sprintf(label, "position\n"); + if (chan->channel == 1) + return sprintf(label, "tracking error\n"); + } + if (chan->type == IIO_ANGL_VEL) + return sprintf(label, "velocity\n"); + if (chan->type == IIO_PHASE) + return sprintf(label, "synthetic reference\n"); + if (chan->type == IIO_ALTVOLTAGE) { + if (chan->output) + return sprintf(label, "excitation\n"); + if (chan->channel == 0) + return sprintf(label, "monitor signal\n"); + if (chan->channel == 1) + return sprintf(label, "cosine\n"); + if (chan->channel == 2) + return sprintf(label, "sine\n"); + } + + return -EINVAL; +} + +static int ad2s1210_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_ANGL: + switch (info) { + case IIO_EV_INFO_VALUE: + return ad2s1210_get_lot_high_threshold(st, val, val2); + case IIO_EV_INFO_HYSTERESIS: + return ad2s1210_get_lot_low_threshold(st, val, val2); + default: + return -EINVAL; + } + case IIO_ALTVOLTAGE: + if (chan->output) + return -EINVAL; + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING) + return ad2s1210_get_voltage_threshold(st, + AD2S1210_REG_LOS_THRD, val); + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING) + return ad2s1210_get_voltage_threshold(st, + AD2S1210_REG_DOS_OVR_THRD, val); + if (type == IIO_EV_TYPE_MAG) + return ad2s1210_get_voltage_threshold(st, + AD2S1210_REG_DOS_MIS_THRD, val); + return -EINVAL; + case IIO_PHASE: + return ad2s1210_get_phase_lock_range(st, val, val2); + default: + return -EINVAL; + } +} + +static int ad2s1210_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + switch (chan->type) { + case IIO_ANGL: + switch (info) { + case IIO_EV_INFO_VALUE: + return ad2s1210_set_lot_high_threshold(st, val, val2); + case IIO_EV_INFO_HYSTERESIS: + return ad2s1210_set_lot_low_threshold(st, val, val2); + default: + return -EINVAL; + } + case IIO_ALTVOLTAGE: + if (chan->output) + return -EINVAL; + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_FALLING) + return ad2s1210_set_voltage_threshold(st, + AD2S1210_REG_LOS_THRD, val); + if (type == IIO_EV_TYPE_THRESH && dir == IIO_EV_DIR_RISING) + return ad2s1210_set_voltage_threshold(st, + AD2S1210_REG_DOS_OVR_THRD, val); + if (type == IIO_EV_TYPE_MAG) + return ad2s1210_set_voltage_threshold(st, + AD2S1210_REG_DOS_MIS_THRD, val); + return -EINVAL; + case IIO_PHASE: + return ad2s1210_set_phase_lock_range(st, val, val2); + default: + return -EINVAL; + } +} + +static int ad2s1210_read_event_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + enum iio_event_type type, + enum iio_event_direction dir, + char *label) +{ + if (chan->type == IIO_ANGL) + return sprintf(label, "LOT\n"); + if (chan->type == IIO_ANGL_VEL) + return sprintf(label, "max tracking rate\n"); + if (chan->type == IIO_PHASE) + return sprintf(label, "phase lock\n"); + if (chan->type == IIO_ALTVOLTAGE) { + if (chan->channel == 0) { + if (type == IIO_EV_TYPE_THRESH && + dir == IIO_EV_DIR_FALLING) + return sprintf(label, "LOS\n"); + if (type == IIO_EV_TYPE_THRESH && + dir == IIO_EV_DIR_RISING) + return sprintf(label, "DOS overrange\n"); + if (type == IIO_EV_TYPE_MAG) + return sprintf(label, "DOS mismatch\n"); + } + if (chan->channel == 1 || chan->channel == 2) + return sprintf(label, "clipped\n"); + } + + return -EINVAL; +} + +static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct ad2s1210_state *st = iio_priv(indio_dev); + + guard(mutex)(&st->lock); + + if (readval) + return regmap_read(st->regmap, reg, readval); + + return regmap_write(st->regmap, reg, writeval); +} + +static irqreturn_t ad2s1210_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad2s1210_state *st = iio_priv(indio_dev); + size_t chan = 0; + int ret; + + guard(mutex)(&st->lock); + + memset(&st->scan, 0, sizeof(st->scan)); + ad2s1210_toggle_sample_line(st); + + if (test_bit(0, indio_dev->active_scan_mask)) { + ret = ad2s1210_set_mode(st, MOD_POS); + if (ret < 0) + goto error_ret; + + ret = spi_read(st->sdev, &st->sample, 3); + if (ret < 0) + goto error_ret; + + memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); + } + + if (test_bit(1, indio_dev->active_scan_mask)) { + ret = ad2s1210_set_mode(st, MOD_VEL); + if (ret < 0) + goto error_ret; + + ret = spi_read(st->sdev, &st->sample, 3); + if (ret < 0) + goto error_ret; + + memcpy(&st->scan.chan[chan++], &st->sample.raw, 2); + } + + ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp); + iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp); + +error_ret: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static const struct iio_info ad2s1210_info = { + .event_attrs = &ad2s1210_event_attribute_group, + .read_raw = ad2s1210_read_raw, + .read_avail = ad2s1210_read_avail, + .write_raw = ad2s1210_write_raw, + .read_label = ad2s1210_read_label, + .read_event_value = ad2s1210_read_event_value, + .write_event_value = ad2s1210_write_event_value, + .read_event_label = ad2s1210_read_event_label, + .debugfs_reg_access = &ad2s1210_debugfs_reg_access, +}; + +static int ad2s1210_setup_properties(struct ad2s1210_state *st) +{ + struct device *dev = &st->sdev->dev; + u32 val; + int ret; + + ret = device_property_read_u32(dev, "assigned-resolution-bits", &val); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to read assigned-resolution-bits property\n"); + + if (val < 10 || val > 16) + return dev_err_probe(dev, -EINVAL, + "resolution out of range: %u\n", val); + + st->resolution = (val - 10) >> 1; + /* + * These are values that correlate to the hysteresis bit in the Control + * register. 0 = disabled, 1 = enabled. When enabled, the actual + * hysteresis is +/- 1 LSB of the raw position value. Which bit is the + * LSB depends on the specified resolution. + */ + st->hysteresis_available[0] = 0; + st->hysteresis_available[1] = 1 << (2 * (AD2S1210_RES_16 - + st->resolution)); + + return 0; +} + +static int ad2s1210_setup_clocks(struct ad2s1210_state *st) +{ + struct device *dev = &st->sdev->dev; + struct clk *clk; + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); + + st->clkin_hz = clk_get_rate(clk); + if (st->clkin_hz < AD2S1210_MIN_CLKIN || st->clkin_hz > AD2S1210_MAX_CLKIN) + return dev_err_probe(dev, -EINVAL, + "clock frequency out of range: %lu\n", + st->clkin_hz); + + return 0; +} + +static int ad2s1210_setup_gpios(struct ad2s1210_state *st) +{ + struct device *dev = &st->sdev->dev; + struct gpio_descs *resolution_gpios; + DECLARE_BITMAP(bitmap, 2); + int ret; + + /* should not be sampling on startup */ + st->sample_gpio = devm_gpiod_get(dev, "sample", GPIOD_OUT_LOW); + if (IS_ERR(st->sample_gpio)) + return dev_err_probe(dev, PTR_ERR(st->sample_gpio), + "failed to request sample GPIO\n"); + + /* both pins high means that we start in config mode */ + st->mode_gpios = devm_gpiod_get_array(dev, "mode", GPIOD_OUT_HIGH); + if (IS_ERR(st->mode_gpios)) + return dev_err_probe(dev, PTR_ERR(st->mode_gpios), + "failed to request mode GPIOs\n"); + + if (st->mode_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, + "requires exactly 2 mode-gpios\n"); + + /* + * If resolution gpios are provided, they get set to the required + * resolution, otherwise it is assumed the RES0 and RES1 pins are + * hard-wired to match the resolution indicated in the devicetree. + */ + resolution_gpios = devm_gpiod_get_array_optional(dev, "resolution", + GPIOD_ASIS); + if (IS_ERR(resolution_gpios)) + return dev_err_probe(dev, PTR_ERR(resolution_gpios), + "failed to request resolution GPIOs\n"); + + if (resolution_gpios) { + if (resolution_gpios->ndescs != 2) + return dev_err_probe(dev, -EINVAL, + "requires exactly 2 resolution-gpios\n"); + + bitmap[0] = st->resolution; + + ret = gpiod_set_array_value(resolution_gpios->ndescs, + resolution_gpios->desc, + resolution_gpios->info, + bitmap); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to set resolution gpios\n"); + } + + return 0; +} + +static const struct regmap_range ad2s1210_regmap_readable_ranges[] = { + regmap_reg_range(AD2S1210_REG_POSITION_MSB, AD2S1210_REG_VELOCITY_LSB), + regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD), + regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL), + regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT), +}; + +static const struct regmap_access_table ad2s1210_regmap_rd_table = { + .yes_ranges = ad2s1210_regmap_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_readable_ranges), +}; + +static const struct regmap_range ad2s1210_regmap_writeable_ranges[] = { + regmap_reg_range(AD2S1210_REG_LOS_THRD, AD2S1210_REG_LOT_LOW_THRD), + regmap_reg_range(AD2S1210_REG_EXCIT_FREQ, AD2S1210_REG_CONTROL), + regmap_reg_range(AD2S1210_REG_SOFT_RESET, AD2S1210_REG_SOFT_RESET), + regmap_reg_range(AD2S1210_REG_FAULT, AD2S1210_REG_FAULT), +}; + +static const struct regmap_access_table ad2s1210_regmap_wr_table = { + .yes_ranges = ad2s1210_regmap_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(ad2s1210_regmap_writeable_ranges), +}; + +static int ad2s1210_setup_regmap(struct ad2s1210_state *st) +{ + struct device *dev = &st->sdev->dev; + const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + .disable_locking = true, + .reg_read = ad2s1210_regmap_reg_read, + .reg_write = ad2s1210_regmap_reg_write, + .rd_table = &ad2s1210_regmap_rd_table, + .wr_table = &ad2s1210_regmap_wr_table, + .can_sleep = true, + }; + + st->regmap = devm_regmap_init(dev, NULL, st, &config); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "failed to allocate register map\n"); + + return 0; +} + +static int ad2s1210_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad2s1210_state *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + st = iio_priv(indio_dev); + + mutex_init(&st->lock); + st->sdev = spi; + + ret = ad2s1210_setup_properties(st); + if (ret < 0) + return ret; + + ret = ad2s1210_setup_clocks(st); + if (ret < 0) + return ret; + + ret = ad2s1210_setup_gpios(st); + if (ret < 0) + return ret; + + ret = ad2s1210_setup_regmap(st); + if (ret < 0) + return ret; + + ret = ad2s1210_initial(st); + if (ret < 0) + return ret; + + indio_dev->info = &ad2s1210_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad2s1210_channels; + indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels); + indio_dev->name = spi_get_device_id(spi)->name; + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, + &ad2s1210_trigger_handler, NULL); + if (ret < 0) + return dev_err_probe(&spi->dev, ret, + "iio triggered buffer setup failed\n"); + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id ad2s1210_of_match[] = { + { .compatible = "adi,ad2s1210", }, + { } +}; +MODULE_DEVICE_TABLE(of, ad2s1210_of_match); + +static const struct spi_device_id ad2s1210_id[] = { + { "ad2s1210" }, + {} +}; +MODULE_DEVICE_TABLE(spi, ad2s1210_id); + +static struct spi_driver ad2s1210_driver = { + .driver = { + .name = "ad2s1210", + .of_match_table = ad2s1210_of_match, + }, + .probe = ad2s1210_probe, + .id_table = ad2s1210_id, +}; +module_spi_driver(ad2s1210_driver); + +MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index d40f235af1d4..0143fd478933 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -257,7 +257,7 @@ error_remove_trigger: } /* Function to deinitialize the processing for usage id */ -static int hid_temperature_remove(struct platform_device *pdev) +static void hid_temperature_remove(struct platform_device *pdev) { struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -265,8 +265,6 @@ static int hid_temperature_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE); hid_sensor_remove_trigger(indio_dev, &temp_st->common_attributes); - - return 0; } static const struct platform_device_id hid_temperature_ids[] = { @@ -285,7 +283,7 @@ static struct platform_driver hid_temperature_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_temperature_probe, - .remove = hid_temperature_remove, + .remove_new = hid_temperature_remove, }; module_platform_driver(hid_temperature_platform_driver); diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 07bb5df24ab3..740018d4b3df 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -600,7 +600,7 @@ static int mlx90614_probe(struct i2c_client *client) data->client = client; mutex_init(&data->lock); data->wakeup_gpio = mlx90614_probe_wakeup(client); - data->chip_info = device_get_match_data(&client->dev); + data->chip_info = i2c_get_match_data(client); mlx90614_wakeup(data); diff --git a/drivers/iio/temperature/tmp117.c b/drivers/iio/temperature/tmp117.c index fc02f491688b..059953015ae7 100644 --- a/drivers/iio/temperature/tmp117.c +++ b/drivers/iio/temperature/tmp117.c @@ -42,6 +42,12 @@ struct tmp117_data { s16 calibbias; }; +struct tmp11x_info { + const char *name; + struct iio_chan_spec const *channels; + int num_channels; +}; + static int tmp117_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask) @@ -119,57 +125,54 @@ static const struct iio_chan_spec tmp116_channels[] = { }, }; +static const struct tmp11x_info tmp116_channels_info = { + .name = "tmp116", + .channels = tmp116_channels, + .num_channels = ARRAY_SIZE(tmp116_channels) +}; + +static const struct tmp11x_info tmp117_channels_info = { + .name = "tmp117", + .channels = tmp117_channels, + .num_channels = ARRAY_SIZE(tmp117_channels) +}; + static const struct iio_info tmp117_info = { .read_raw = tmp117_read_raw, .write_raw = tmp117_write_raw, }; -static int tmp117_identify(struct i2c_client *client) +static int tmp117_probe(struct i2c_client *client) { - const struct i2c_device_id *id; - unsigned long match_data; + const struct tmp11x_info *match_data; + struct tmp117_data *data; + struct iio_dev *indio_dev; int dev_id; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -EOPNOTSUPP; + dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID); if (dev_id < 0) return dev_id; switch (dev_id) { case TMP116_DEVICE_ID: + match_data = &tmp116_channels_info; + break; case TMP117_DEVICE_ID: - return dev_id; + match_data = &tmp117_channels_info; + break; + default: + dev_info(&client->dev, + "Unknown device id (0x%x), use fallback compatible\n", + dev_id); + match_data = i2c_get_match_data(client); } - dev_info(&client->dev, "Unknown device id (0x%x), use fallback compatible\n", - dev_id); - - match_data = (uintptr_t)device_get_match_data(&client->dev); - if (match_data) - return match_data; - - id = i2c_client_get_device_id(client); - if (id) - return id->driver_data; - - dev_err(&client->dev, "Failed to identify unsupported device\n"); - - return -ENODEV; -} - -static int tmp117_probe(struct i2c_client *client) -{ - struct tmp117_data *data; - struct iio_dev *indio_dev; - int ret, dev_id; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) - return -EOPNOTSUPP; - - ret = tmp117_identify(client); - if (ret < 0) - return ret; - - dev_id = ret; + if (!match_data) + return dev_err_probe(&client->dev, -ENODEV, + "Failed to identify unsupported device\n"); indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -181,33 +184,24 @@ static int tmp117_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &tmp117_info; + indio_dev->channels = match_data->channels; + indio_dev->num_channels = match_data->num_channels; + indio_dev->name = match_data->name; - switch (dev_id) { - case TMP116_DEVICE_ID: - indio_dev->channels = tmp116_channels; - indio_dev->num_channels = ARRAY_SIZE(tmp116_channels); - indio_dev->name = "tmp116"; - break; - case TMP117_DEVICE_ID: - indio_dev->channels = tmp117_channels; - indio_dev->num_channels = ARRAY_SIZE(tmp117_channels); - indio_dev->name = "tmp117"; - break; - } return devm_iio_device_register(&client->dev, indio_dev); } static const struct of_device_id tmp117_of_match[] = { - { .compatible = "ti,tmp116", .data = (void *)TMP116_DEVICE_ID }, - { .compatible = "ti,tmp117", .data = (void *)TMP117_DEVICE_ID }, + { .compatible = "ti,tmp116", .data = &tmp116_channels_info }, + { .compatible = "ti,tmp117", .data = &tmp117_channels_info }, { } }; MODULE_DEVICE_TABLE(of, tmp117_of_match); static const struct i2c_device_id tmp117_id[] = { - { "tmp116", TMP116_DEVICE_ID }, - { "tmp117", TMP117_DEVICE_ID }, + { "tmp116", (kernel_ulong_t)&tmp116_channels_info }, + { "tmp117", (kernel_ulong_t)&tmp117_channels_info }, { } }; MODULE_DEVICE_TABLE(i2c, tmp117_id); diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 5f49cd105fae..dec256bfbd73 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -81,7 +81,7 @@ error_ret: return ret; } -static int iio_interrupt_trigger_remove(struct platform_device *pdev) +static void iio_interrupt_trigger_remove(struct platform_device *pdev) { struct iio_trigger *trig; struct iio_interrupt_trigger_info *trig_info; @@ -92,13 +92,11 @@ static int iio_interrupt_trigger_remove(struct platform_device *pdev) free_irq(trig_info->irq, trig); kfree(trig_info); iio_trigger_free(trig); - - return 0; } static struct platform_driver iio_interrupt_trigger_driver = { .probe = iio_interrupt_trigger_probe, - .remove = iio_interrupt_trigger_remove, + .remove_new = iio_interrupt_trigger_remove, .driver = { .name = "iio_interrupt_trigger", }, diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 3643c4afae67..d76444030a28 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -809,7 +809,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) return 0; } -static int stm32_timer_trigger_remove(struct platform_device *pdev) +static void stm32_timer_trigger_remove(struct platform_device *pdev) { struct stm32_timer_trigger *priv = platform_get_drvdata(pdev); u32 val; @@ -824,8 +824,6 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev) if (priv->enabled) clk_disable(priv->clk); - - return 0; } static int stm32_timer_trigger_suspend(struct device *dev) @@ -904,7 +902,7 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match); static struct platform_driver stm32_timer_trigger_driver = { .probe = stm32_timer_trigger_probe, - .remove = stm32_timer_trigger_remove, + .remove_new = stm32_timer_trigger_remove, .driver = { .name = "stm32-timer-trigger", .of_match_table = stm32_trig_of_match, |