| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * AD5446 SPI DAC driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2010 Analog Devices Inc. |
|---|
| 5 | | - * |
|---|
| 6 | | - * Licensed under the GPL-2 or later. |
|---|
| 7 | 6 | */ |
|---|
| 8 | 7 | |
|---|
| 9 | 8 | #include <linux/interrupt.h> |
|---|
| .. | .. |
|---|
| 18 | 17 | #include <linux/regulator/consumer.h> |
|---|
| 19 | 18 | #include <linux/err.h> |
|---|
| 20 | 19 | #include <linux/module.h> |
|---|
| 20 | +#include <linux/mod_devicetable.h> |
|---|
| 21 | 21 | |
|---|
| 22 | 22 | #include <linux/iio/iio.h> |
|---|
| 23 | 23 | #include <linux/iio/sysfs.h> |
|---|
| 24 | + |
|---|
| 25 | +#include <asm/unaligned.h> |
|---|
| 24 | 26 | |
|---|
| 25 | 27 | #define MODE_PWRDWN_1k 0x1 |
|---|
| 26 | 28 | #define MODE_PWRDWN_100k 0x2 |
|---|
| .. | .. |
|---|
| 28 | 30 | |
|---|
| 29 | 31 | /** |
|---|
| 30 | 32 | * struct ad5446_state - driver instance specific data |
|---|
| 31 | | - * @spi: spi_device |
|---|
| 33 | + * @dev: this device |
|---|
| 32 | 34 | * @chip_info: chip model specific constants, available modes etc |
|---|
| 33 | 35 | * @reg: supply regulator |
|---|
| 34 | 36 | * @vref_mv: actual reference voltage used |
|---|
| 37 | + * @cached_val: store/retrieve values during power down |
|---|
| 38 | + * @pwr_down_mode: power down mode (1k, 100k or tristate) |
|---|
| 39 | + * @pwr_down: true if the device is in power down |
|---|
| 40 | + * @lock: lock to protect the data buffer during write ops |
|---|
| 35 | 41 | */ |
|---|
| 36 | 42 | |
|---|
| 37 | 43 | struct ad5446_state { |
|---|
| .. | .. |
|---|
| 42 | 48 | unsigned cached_val; |
|---|
| 43 | 49 | unsigned pwr_down_mode; |
|---|
| 44 | 50 | unsigned pwr_down; |
|---|
| 51 | + struct mutex lock; |
|---|
| 45 | 52 | }; |
|---|
| 46 | 53 | |
|---|
| 47 | 54 | /** |
|---|
| .. | .. |
|---|
| 111 | 118 | if (ret) |
|---|
| 112 | 119 | return ret; |
|---|
| 113 | 120 | |
|---|
| 114 | | - mutex_lock(&indio_dev->mlock); |
|---|
| 121 | + mutex_lock(&st->lock); |
|---|
| 115 | 122 | st->pwr_down = powerdown; |
|---|
| 116 | 123 | |
|---|
| 117 | 124 | if (st->pwr_down) { |
|---|
| .. | .. |
|---|
| 122 | 129 | } |
|---|
| 123 | 130 | |
|---|
| 124 | 131 | ret = st->chip_info->write(st, val); |
|---|
| 125 | | - mutex_unlock(&indio_dev->mlock); |
|---|
| 132 | + mutex_unlock(&st->lock); |
|---|
| 126 | 133 | |
|---|
| 127 | 134 | return ret ? ret : len; |
|---|
| 128 | 135 | } |
|---|
| .. | .. |
|---|
| 171 | 178 | |
|---|
| 172 | 179 | switch (m) { |
|---|
| 173 | 180 | case IIO_CHAN_INFO_RAW: |
|---|
| 174 | | - *val = st->cached_val; |
|---|
| 181 | + *val = st->cached_val >> chan->scan_type.shift; |
|---|
| 175 | 182 | return IIO_VAL_INT; |
|---|
| 176 | 183 | case IIO_CHAN_INFO_SCALE: |
|---|
| 177 | 184 | *val = st->vref_mv; |
|---|
| .. | .. |
|---|
| 196 | 203 | return -EINVAL; |
|---|
| 197 | 204 | |
|---|
| 198 | 205 | val <<= chan->scan_type.shift; |
|---|
| 199 | | - mutex_lock(&indio_dev->mlock); |
|---|
| 206 | + mutex_lock(&st->lock); |
|---|
| 200 | 207 | st->cached_val = val; |
|---|
| 201 | 208 | if (!st->pwr_down) |
|---|
| 202 | 209 | ret = st->chip_info->write(st, val); |
|---|
| 203 | | - mutex_unlock(&indio_dev->mlock); |
|---|
| 210 | + mutex_unlock(&st->lock); |
|---|
| 204 | 211 | break; |
|---|
| 205 | 212 | default: |
|---|
| 206 | 213 | ret = -EINVAL; |
|---|
| .. | .. |
|---|
| 247 | 254 | st->reg = reg; |
|---|
| 248 | 255 | st->dev = dev; |
|---|
| 249 | 256 | |
|---|
| 250 | | - /* Establish that the iio_dev is a child of the device */ |
|---|
| 251 | | - indio_dev->dev.parent = dev; |
|---|
| 252 | 257 | indio_dev->name = name; |
|---|
| 253 | 258 | indio_dev->info = &ad5446_info; |
|---|
| 254 | 259 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 255 | 260 | indio_dev->channels = &st->chip_info->channel; |
|---|
| 256 | 261 | indio_dev->num_channels = 1; |
|---|
| 262 | + |
|---|
| 263 | + mutex_init(&st->lock); |
|---|
| 257 | 264 | |
|---|
| 258 | 265 | st->pwr_down_mode = MODE_PWRDWN_1k; |
|---|
| 259 | 266 | |
|---|
| .. | .. |
|---|
| 303 | 310 | struct spi_device *spi = to_spi_device(st->dev); |
|---|
| 304 | 311 | uint8_t data[3]; |
|---|
| 305 | 312 | |
|---|
| 306 | | - data[0] = (val >> 16) & 0xFF; |
|---|
| 307 | | - data[1] = (val >> 8) & 0xFF; |
|---|
| 308 | | - data[2] = val & 0xFF; |
|---|
| 313 | + put_unaligned_be24(val, &data[0]); |
|---|
| 309 | 314 | |
|---|
| 310 | 315 | return spi_write(spi, data, sizeof(data)); |
|---|
| 311 | 316 | } |
|---|
| 312 | 317 | |
|---|
| 313 | | -/** |
|---|
| 318 | +/* |
|---|
| 314 | 319 | * ad5446_supported_spi_device_ids: |
|---|
| 315 | 320 | * The AD5620/40/60 parts are available in different fixed internal reference |
|---|
| 316 | 321 | * voltage options. The actual part numbers may look differently |
|---|
| .. | .. |
|---|
| 474 | 479 | }; |
|---|
| 475 | 480 | MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); |
|---|
| 476 | 481 | |
|---|
| 477 | | -#ifdef CONFIG_OF |
|---|
| 478 | 482 | static const struct of_device_id ad5446_of_ids[] = { |
|---|
| 479 | 483 | { .compatible = "ti,dac7512" }, |
|---|
| 480 | 484 | { } |
|---|
| 481 | 485 | }; |
|---|
| 482 | 486 | MODULE_DEVICE_TABLE(of, ad5446_of_ids); |
|---|
| 483 | | -#endif |
|---|
| 484 | 487 | |
|---|
| 485 | 488 | static int ad5446_spi_probe(struct spi_device *spi) |
|---|
| 486 | 489 | { |
|---|
| .. | .. |
|---|
| 498 | 501 | static struct spi_driver ad5446_spi_driver = { |
|---|
| 499 | 502 | .driver = { |
|---|
| 500 | 503 | .name = "ad5446", |
|---|
| 501 | | - .of_match_table = of_match_ptr(ad5446_of_ids), |
|---|
| 504 | + .of_match_table = ad5446_of_ids, |
|---|
| 502 | 505 | }, |
|---|
| 503 | 506 | .probe = ad5446_spi_probe, |
|---|
| 504 | 507 | .remove = ad5446_spi_remove, |
|---|
| .. | .. |
|---|
| 539 | 542 | return 0; |
|---|
| 540 | 543 | } |
|---|
| 541 | 544 | |
|---|
| 542 | | -/** |
|---|
| 545 | +/* |
|---|
| 543 | 546 | * ad5446_supported_i2c_device_ids: |
|---|
| 544 | 547 | * The AD5620/40/60 parts are available in different fixed internal reference |
|---|
| 545 | 548 | * voltage options. The actual part numbers may look differently |
|---|
| .. | .. |
|---|
| 641 | 644 | } |
|---|
| 642 | 645 | module_exit(ad5446_exit); |
|---|
| 643 | 646 | |
|---|
| 644 | | -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); |
|---|
| 647 | +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
|---|
| 645 | 648 | MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); |
|---|
| 646 | 649 | MODULE_LICENSE("GPL v2"); |
|---|