Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: dac: ad3530r: Add driver for AD3530R and AD3531R

The AD3530/AD3530R (8-channel) and AD3531/AD3531R (4-channel) are
low-power, 16-bit, buffered voltage output DACs with software-
programmable gain controls, providing full-scale output spans of 2.5V or
5V for reference voltages of 2.5V. These devices operate from a single
2.7V to 5.5V supply and are guaranteed monotonic by design. The "R"
variants include a 2.5V, 5ppm/°C internal reference, which is disabled
by default.

Support for monitoring internal die temperature, output voltages, and
current of a selected channel via the MUXOUT pin using an external ADC
is currently not implemented.

Reviewed-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Link: https://patch.msgid.link/20250429-togreg-v7-3-0af9c543b545@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Kim Seer Paller and committed by
Jonathan Cameron
93583174 6856e361

+530
+1
MAINTAINERS
··· 1306 1306 S: Supported 1307 1307 W: https://ez.analog.com/linux-software-drivers 1308 1308 F: Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml 1309 + F: drivers/iio/dac/ad3530r.c 1309 1310 1310 1311 ANALOG DEVICES INC AD3552R DRIVER 1311 1312 M: Nuno Sá <nuno.sa@analog.com>
+11
drivers/iio/dac/Kconfig
··· 6 6 7 7 menu "Digital to analog converters" 8 8 9 + config AD3530R 10 + tristate "Analog Devices AD3530R and Similar DACs driver" 11 + depends on SPI 12 + select REGMAP_SPI 13 + help 14 + Say yes here to build support for Analog Devices AD3530R, AD3531R 15 + Digital to Analog Converter. 16 + 17 + To compile this driver as a module, choose M here: the 18 + module will be called ad3530r. 19 + 9 20 config AD3552R_HS 10 21 tristate "Analog Devices AD3552R DAC High Speed driver" 11 22 select AD3552R_LIB
+1
drivers/iio/dac/Makefile
··· 4 4 # 5 5 6 6 # When adding new entries keep the list in alphabetical order 7 + obj-$(CONFIG_AD3530R) += ad3530r.o 7 8 obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o 8 9 obj-$(CONFIG_AD3552R_LIB) += ad3552r-common.o 9 10 obj-$(CONFIG_AD3552R) += ad3552r.o
+517
drivers/iio/dac/ad3530r.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver 4 + * AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver 5 + * 6 + * Copyright 2025 Analog Devices Inc. 7 + */ 8 + 9 + #include <linux/array_size.h> 10 + #include <linux/bitfield.h> 11 + #include <linux/bits.h> 12 + #include <linux/cleanup.h> 13 + #include <linux/delay.h> 14 + #include <linux/dev_printk.h> 15 + #include <linux/err.h> 16 + #include <linux/gpio/consumer.h> 17 + #include <linux/iio/iio.h> 18 + #include <linux/kstrtox.h> 19 + #include <linux/mod_devicetable.h> 20 + #include <linux/module.h> 21 + #include <linux/mutex.h> 22 + #include <linux/property.h> 23 + #include <linux/regmap.h> 24 + #include <linux/regulator/consumer.h> 25 + #include <linux/spi/spi.h> 26 + #include <linux/sysfs.h> 27 + #include <linux/types.h> 28 + #include <linux/units.h> 29 + 30 + #define AD3530R_INTERFACE_CONFIG_A 0x00 31 + #define AD3530R_OUTPUT_OPERATING_MODE_0 0x20 32 + #define AD3530R_OUTPUT_OPERATING_MODE_1 0x21 33 + #define AD3530R_OUTPUT_CONTROL_0 0x2A 34 + #define AD3530R_REFERENCE_CONTROL_0 0x3C 35 + #define AD3530R_SW_LDAC_TRIG_A 0xE5 36 + #define AD3530R_INPUT_CH 0xEB 37 + #define AD3530R_MAX_REG_ADDR 0xF9 38 + 39 + #define AD3531R_SW_LDAC_TRIG_A 0xDD 40 + #define AD3531R_INPUT_CH 0xE3 41 + 42 + #define AD3530R_SLD_TRIG_A BIT(7) 43 + #define AD3530R_OUTPUT_CONTROL_RANGE BIT(2) 44 + #define AD3530R_REFERENCE_CONTROL_SEL BIT(0) 45 + #define AD3530R_REG_VAL_MASK GENMASK(15, 0) 46 + #define AD3530R_OP_MODE_CHAN_MSK(chan) (GENMASK(1, 0) << 2 * (chan)) 47 + 48 + #define AD3530R_SW_RESET (BIT(7) | BIT(0)) 49 + #define AD3530R_INTERNAL_VREF_mV 2500 50 + #define AD3530R_LDAC_PULSE_US 100 51 + 52 + #define AD3530R_DAC_MAX_VAL GENMASK(15, 0) 53 + #define AD3530R_MAX_CHANNELS 8 54 + #define AD3531R_MAX_CHANNELS 4 55 + 56 + /* Non-constant mask variant of FIELD_PREP() */ 57 + #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) 58 + 59 + enum ad3530r_mode { 60 + AD3530R_NORMAL_OP, 61 + AD3530R_POWERDOWN_1K, 62 + AD3530R_POWERDOWN_7K7, 63 + AD3530R_POWERDOWN_32K, 64 + }; 65 + 66 + struct ad3530r_chan { 67 + enum ad3530r_mode powerdown_mode; 68 + bool powerdown; 69 + }; 70 + 71 + struct ad3530r_chip_info { 72 + const char *name; 73 + const struct iio_chan_spec *channels; 74 + int (*input_ch_reg)(unsigned int channel); 75 + unsigned int num_channels; 76 + unsigned int sw_ldac_trig_reg; 77 + bool internal_ref_support; 78 + }; 79 + 80 + struct ad3530r_state { 81 + struct regmap *regmap; 82 + /* lock to protect against multiple access to the device and shared data */ 83 + struct mutex lock; 84 + struct ad3530r_chan chan[AD3530R_MAX_CHANNELS]; 85 + const struct ad3530r_chip_info *chip_info; 86 + struct gpio_desc *ldac_gpio; 87 + int vref_mV; 88 + /* 89 + * DMA (thus cache coherency maintenance) may require the transfer 90 + * buffers to live in their own cache lines. 91 + */ 92 + __be16 buf __aligned(IIO_DMA_MINALIGN); 93 + }; 94 + 95 + static int ad3530r_input_ch_reg(unsigned int channel) 96 + { 97 + return 2 * channel + AD3530R_INPUT_CH; 98 + } 99 + 100 + static int ad3531r_input_ch_reg(unsigned int channel) 101 + { 102 + return 2 * channel + AD3531R_INPUT_CH; 103 + } 104 + 105 + static const char * const ad3530r_powerdown_modes[] = { 106 + "1kohm_to_gnd", 107 + "7.7kohm_to_gnd", 108 + "32kohm_to_gnd", 109 + }; 110 + 111 + static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev, 112 + const struct iio_chan_spec *chan) 113 + { 114 + struct ad3530r_state *st = iio_priv(indio_dev); 115 + 116 + guard(mutex)(&st->lock); 117 + return st->chan[chan->channel].powerdown_mode - 1; 118 + } 119 + 120 + static int ad3530r_set_powerdown_mode(struct iio_dev *indio_dev, 121 + const struct iio_chan_spec *chan, 122 + unsigned int mode) 123 + { 124 + struct ad3530r_state *st = iio_priv(indio_dev); 125 + 126 + guard(mutex)(&st->lock); 127 + st->chan[chan->channel].powerdown_mode = mode + 1; 128 + 129 + return 0; 130 + } 131 + 132 + static const struct iio_enum ad3530r_powerdown_mode_enum = { 133 + .items = ad3530r_powerdown_modes, 134 + .num_items = ARRAY_SIZE(ad3530r_powerdown_modes), 135 + .get = ad3530r_get_powerdown_mode, 136 + .set = ad3530r_set_powerdown_mode, 137 + }; 138 + 139 + static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev, 140 + uintptr_t private, 141 + const struct iio_chan_spec *chan, 142 + char *buf) 143 + { 144 + struct ad3530r_state *st = iio_priv(indio_dev); 145 + 146 + guard(mutex)(&st->lock); 147 + return sysfs_emit(buf, "%d\n", st->chan[chan->channel].powerdown); 148 + } 149 + 150 + static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev, 151 + uintptr_t private, 152 + const struct iio_chan_spec *chan, 153 + const char *buf, size_t len) 154 + { 155 + struct ad3530r_state *st = iio_priv(indio_dev); 156 + int ret; 157 + unsigned int reg, pdmode, mask, val; 158 + bool powerdown; 159 + 160 + ret = kstrtobool(buf, &powerdown); 161 + if (ret) 162 + return ret; 163 + 164 + guard(mutex)(&st->lock); 165 + reg = chan->channel < AD3531R_MAX_CHANNELS ? 166 + AD3530R_OUTPUT_OPERATING_MODE_0 : 167 + AD3530R_OUTPUT_OPERATING_MODE_1; 168 + pdmode = powerdown ? st->chan[chan->channel].powerdown_mode : 0; 169 + mask = AD3530R_OP_MODE_CHAN_MSK(chan->channel); 170 + val = field_prep(mask, pdmode); 171 + 172 + ret = regmap_update_bits(st->regmap, reg, mask, val); 173 + if (ret) 174 + return ret; 175 + 176 + st->chan[chan->channel].powerdown = powerdown; 177 + 178 + return len; 179 + } 180 + 181 + static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio) 182 + { 183 + gpiod_set_value_cansleep(ldac_gpio, 1); 184 + fsleep(AD3530R_LDAC_PULSE_US); 185 + gpiod_set_value_cansleep(ldac_gpio, 0); 186 + 187 + return 0; 188 + } 189 + 190 + static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan, 191 + unsigned int val) 192 + { 193 + int ret; 194 + 195 + guard(mutex)(&st->lock); 196 + st->buf = cpu_to_be16(val); 197 + 198 + ret = regmap_bulk_write(st->regmap, st->chip_info->input_ch_reg(chan), 199 + &st->buf, sizeof(st->buf)); 200 + if (ret) 201 + return ret; 202 + 203 + if (st->ldac_gpio) 204 + return ad3530r_trigger_hw_ldac(st->ldac_gpio); 205 + 206 + return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg, 207 + AD3530R_SLD_TRIG_A); 208 + } 209 + 210 + static int ad3530r_read_raw(struct iio_dev *indio_dev, 211 + struct iio_chan_spec const *chan, 212 + int *val, int *val2, long info) 213 + { 214 + struct ad3530r_state *st = iio_priv(indio_dev); 215 + int ret; 216 + 217 + guard(mutex)(&st->lock); 218 + switch (info) { 219 + case IIO_CHAN_INFO_RAW: 220 + ret = regmap_bulk_read(st->regmap, 221 + st->chip_info->input_ch_reg(chan->channel), 222 + &st->buf, sizeof(st->buf)); 223 + if (ret) 224 + return ret; 225 + 226 + *val = FIELD_GET(AD3530R_REG_VAL_MASK, be16_to_cpu(st->buf)); 227 + 228 + return IIO_VAL_INT; 229 + case IIO_CHAN_INFO_SCALE: 230 + *val = st->vref_mV; 231 + *val2 = 16; 232 + 233 + return IIO_VAL_FRACTIONAL_LOG2; 234 + default: 235 + return -EINVAL; 236 + } 237 + } 238 + 239 + static int ad3530r_write_raw(struct iio_dev *indio_dev, 240 + struct iio_chan_spec const *chan, 241 + int val, int val2, long info) 242 + { 243 + struct ad3530r_state *st = iio_priv(indio_dev); 244 + 245 + switch (info) { 246 + case IIO_CHAN_INFO_RAW: 247 + if (val < 0 || val > AD3530R_DAC_MAX_VAL) 248 + return -EINVAL; 249 + 250 + return ad3530r_dac_write(st, chan->channel, val); 251 + default: 252 + return -EINVAL; 253 + } 254 + } 255 + 256 + static int ad3530r_reg_access(struct iio_dev *indio_dev, unsigned int reg, 257 + unsigned int writeval, unsigned int *readval) 258 + { 259 + struct ad3530r_state *st = iio_priv(indio_dev); 260 + 261 + if (readval) 262 + return regmap_read(st->regmap, reg, readval); 263 + 264 + return regmap_write(st->regmap, reg, writeval); 265 + } 266 + 267 + static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = { 268 + { 269 + .name = "powerdown", 270 + .shared = IIO_SEPARATE, 271 + .read = ad3530r_get_dac_powerdown, 272 + .write = ad3530r_set_dac_powerdown, 273 + }, 274 + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3530r_powerdown_mode_enum), 275 + IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, 276 + &ad3530r_powerdown_mode_enum), 277 + { } 278 + }; 279 + 280 + #define AD3530R_CHAN(_chan) \ 281 + { \ 282 + .type = IIO_VOLTAGE, \ 283 + .indexed = 1, \ 284 + .channel = _chan, \ 285 + .output = 1, \ 286 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 287 + BIT(IIO_CHAN_INFO_SCALE), \ 288 + .ext_info = ad3530r_ext_info, \ 289 + } 290 + 291 + static const struct iio_chan_spec ad3530r_channels[] = { 292 + AD3530R_CHAN(0), 293 + AD3530R_CHAN(1), 294 + AD3530R_CHAN(2), 295 + AD3530R_CHAN(3), 296 + AD3530R_CHAN(4), 297 + AD3530R_CHAN(5), 298 + AD3530R_CHAN(6), 299 + AD3530R_CHAN(7), 300 + }; 301 + 302 + static const struct iio_chan_spec ad3531r_channels[] = { 303 + AD3530R_CHAN(0), 304 + AD3530R_CHAN(1), 305 + AD3530R_CHAN(2), 306 + AD3530R_CHAN(3), 307 + }; 308 + 309 + static const struct ad3530r_chip_info ad3530_chip = { 310 + .name = "ad3530", 311 + .channels = ad3530r_channels, 312 + .num_channels = ARRAY_SIZE(ad3530r_channels), 313 + .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, 314 + .input_ch_reg = ad3530r_input_ch_reg, 315 + .internal_ref_support = false, 316 + }; 317 + 318 + static const struct ad3530r_chip_info ad3530r_chip = { 319 + .name = "ad3530r", 320 + .channels = ad3530r_channels, 321 + .num_channels = ARRAY_SIZE(ad3530r_channels), 322 + .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A, 323 + .input_ch_reg = ad3530r_input_ch_reg, 324 + .internal_ref_support = true, 325 + }; 326 + 327 + static const struct ad3530r_chip_info ad3531_chip = { 328 + .name = "ad3531", 329 + .channels = ad3531r_channels, 330 + .num_channels = ARRAY_SIZE(ad3531r_channels), 331 + .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, 332 + .input_ch_reg = ad3531r_input_ch_reg, 333 + .internal_ref_support = false, 334 + }; 335 + 336 + static const struct ad3530r_chip_info ad3531r_chip = { 337 + .name = "ad3531r", 338 + .channels = ad3531r_channels, 339 + .num_channels = ARRAY_SIZE(ad3531r_channels), 340 + .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A, 341 + .input_ch_reg = ad3531r_input_ch_reg, 342 + .internal_ref_support = true, 343 + }; 344 + 345 + static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV) 346 + { 347 + struct device *dev = regmap_get_device(st->regmap); 348 + struct gpio_desc *reset_gpio; 349 + int i, ret; 350 + u8 range_multiplier, val; 351 + 352 + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 353 + if (IS_ERR(reset_gpio)) 354 + return dev_err_probe(dev, PTR_ERR(reset_gpio), 355 + "Failed to get reset GPIO\n"); 356 + 357 + if (reset_gpio) { 358 + /* Perform hardware reset */ 359 + fsleep(1 * USEC_PER_MSEC); 360 + gpiod_set_value_cansleep(reset_gpio, 0); 361 + } else { 362 + /* Perform software reset */ 363 + ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A, 364 + AD3530R_SW_RESET, AD3530R_SW_RESET); 365 + if (ret) 366 + return ret; 367 + } 368 + 369 + fsleep(10 * USEC_PER_MSEC); 370 + 371 + range_multiplier = 1; 372 + if (device_property_read_bool(dev, "adi,range-double")) { 373 + ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0, 374 + AD3530R_OUTPUT_CONTROL_RANGE); 375 + if (ret) 376 + return ret; 377 + 378 + range_multiplier = 2; 379 + } 380 + 381 + if (external_vref_uV) { 382 + st->vref_mV = range_multiplier * external_vref_uV / MILLI; 383 + } else { 384 + ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0, 385 + AD3530R_REFERENCE_CONTROL_SEL); 386 + if (ret) 387 + return ret; 388 + 389 + st->vref_mV = range_multiplier * AD3530R_INTERNAL_VREF_mV; 390 + } 391 + 392 + /* Set normal operating mode for all channels */ 393 + val = FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(0), AD3530R_NORMAL_OP) | 394 + FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(1), AD3530R_NORMAL_OP) | 395 + FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) | 396 + FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP); 397 + 398 + ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val); 399 + if (ret) 400 + return ret; 401 + 402 + if (st->chip_info->num_channels > 4) { 403 + ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1, 404 + val); 405 + if (ret) 406 + return ret; 407 + } 408 + 409 + for (i = 0; i < st->chip_info->num_channels; i++) 410 + st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K; 411 + 412 + st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW); 413 + if (IS_ERR(st->ldac_gpio)) 414 + return dev_err_probe(dev, PTR_ERR(st->ldac_gpio), 415 + "Failed to get ldac GPIO\n"); 416 + 417 + return 0; 418 + } 419 + 420 + static const struct regmap_config ad3530r_regmap_config = { 421 + .reg_bits = 16, 422 + .val_bits = 8, 423 + .max_register = AD3530R_MAX_REG_ADDR, 424 + }; 425 + 426 + static const struct iio_info ad3530r_info = { 427 + .read_raw = ad3530r_read_raw, 428 + .write_raw = ad3530r_write_raw, 429 + .debugfs_reg_access = ad3530r_reg_access, 430 + }; 431 + 432 + static int ad3530r_probe(struct spi_device *spi) 433 + { 434 + static const char * const regulators[] = { "vdd", "iovdd" }; 435 + struct device *dev = &spi->dev; 436 + struct iio_dev *indio_dev; 437 + struct ad3530r_state *st; 438 + int ret, external_vref_uV; 439 + 440 + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 441 + if (!indio_dev) 442 + return -ENOMEM; 443 + 444 + st = iio_priv(indio_dev); 445 + 446 + st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config); 447 + if (IS_ERR(st->regmap)) 448 + return dev_err_probe(dev, PTR_ERR(st->regmap), 449 + "Failed to init regmap"); 450 + 451 + ret = devm_mutex_init(dev, &st->lock); 452 + if (ret) 453 + return ret; 454 + 455 + st->chip_info = spi_get_device_match_data(spi); 456 + if (!st->chip_info) 457 + return -ENODEV; 458 + 459 + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators), 460 + regulators); 461 + if (ret) 462 + return dev_err_probe(dev, ret, "Failed to enable regulators\n"); 463 + 464 + external_vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref"); 465 + if (external_vref_uV < 0 && external_vref_uV != -ENODEV) 466 + return external_vref_uV; 467 + 468 + if (external_vref_uV == -ENODEV) 469 + external_vref_uV = 0; 470 + 471 + if (!st->chip_info->internal_ref_support && external_vref_uV == 0) 472 + return -ENODEV; 473 + 474 + ret = ad3530r_setup(st, external_vref_uV); 475 + if (ret) 476 + return ret; 477 + 478 + indio_dev->name = st->chip_info->name; 479 + indio_dev->info = &ad3530r_info; 480 + indio_dev->modes = INDIO_DIRECT_MODE; 481 + indio_dev->channels = st->chip_info->channels; 482 + indio_dev->num_channels = st->chip_info->num_channels; 483 + 484 + return devm_iio_device_register(&spi->dev, indio_dev); 485 + } 486 + 487 + static const struct spi_device_id ad3530r_id[] = { 488 + { "ad3530", (kernel_ulong_t)&ad3530_chip }, 489 + { "ad3530r", (kernel_ulong_t)&ad3530r_chip }, 490 + { "ad3531", (kernel_ulong_t)&ad3531_chip }, 491 + { "ad3531r", (kernel_ulong_t)&ad3531r_chip }, 492 + { } 493 + }; 494 + MODULE_DEVICE_TABLE(spi, ad3530r_id); 495 + 496 + static const struct of_device_id ad3530r_of_match[] = { 497 + { .compatible = "adi,ad3530", .data = &ad3530_chip }, 498 + { .compatible = "adi,ad3530r", .data = &ad3530r_chip }, 499 + { .compatible = "adi,ad3531", .data = &ad3531_chip }, 500 + { .compatible = "adi,ad3531r", .data = &ad3531r_chip }, 501 + { } 502 + }; 503 + MODULE_DEVICE_TABLE(of, ad3530r_of_match); 504 + 505 + static struct spi_driver ad3530r_driver = { 506 + .driver = { 507 + .name = "ad3530r", 508 + .of_match_table = ad3530r_of_match, 509 + }, 510 + .probe = ad3530r_probe, 511 + .id_table = ad3530r_id, 512 + }; 513 + module_spi_driver(ad3530r_driver); 514 + 515 + MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>"); 516 + MODULE_DESCRIPTION("Analog Devices AD3530R and Similar DACs Driver"); 517 + MODULE_LICENSE("GPL");