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

iio: dac: mcp4725: support voltage reference selection

MCP47x6 chip supports selection of a voltage reference (VDD, VREF buffered
or unbuffered). MCP4725 doesn't have this feature thus the eventual setting
is ignored and user is warned.

The setting is stored only in the volatile memory of the chip. You need to
manually store it to the EEPROM of the chip via 'store_eeprom' sysfs entry.

Signed-off-by: Tomas Novotny <tomas@novotny.cz>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Tomas Novotny and committed by
Jonathan Cameron
29157c6d 8b0ee39f

+102 -6
+91 -6
drivers/iio/dac/mcp4725.c
··· 27 27 28 28 #define MCP4725_DRV_NAME "mcp4725" 29 29 30 + #define MCP472X_REF_VDD 0x00 31 + #define MCP472X_REF_VREF_UNBUFFERED 0x02 32 + #define MCP472X_REF_VREF_BUFFERED 0x03 33 + 30 34 struct mcp4725_data { 31 35 struct i2c_client *client; 36 + int id; 37 + unsigned ref_mode; 38 + bool vref_buffered; 32 39 u16 dac_value; 33 40 bool powerdown; 34 41 unsigned powerdown_mode; 35 42 struct regulator *vdd_reg; 43 + struct regulator *vref_reg; 36 44 }; 37 45 38 46 static int mcp4725_suspend(struct device *dev) ··· 95 87 return 0; 96 88 97 89 inoutbuf[0] = 0x60; /* write EEPROM */ 90 + inoutbuf[0] |= data->ref_mode << 3; 98 91 inoutbuf[1] = data->dac_value >> 4; 99 92 inoutbuf[2] = (data->dac_value & 0xf) << 4; 100 93 ··· 288 279 return 0; 289 280 } 290 281 282 + static int mcp4726_set_cfg(struct iio_dev *indio_dev) 283 + { 284 + struct mcp4725_data *data = iio_priv(indio_dev); 285 + u8 outbuf[3]; 286 + int ret; 287 + 288 + outbuf[0] = 0x40; 289 + outbuf[0] |= data->ref_mode << 3; 290 + if (data->powerdown) 291 + outbuf[0] |= data->powerdown << 1; 292 + outbuf[1] = data->dac_value >> 4; 293 + outbuf[2] = (data->dac_value & 0xf) << 4; 294 + 295 + ret = i2c_master_send(data->client, outbuf, 3); 296 + if (ret < 0) 297 + return ret; 298 + else if (ret != 3) 299 + return -EIO; 300 + else 301 + return 0; 302 + } 303 + 291 304 static int mcp4725_read_raw(struct iio_dev *indio_dev, 292 305 struct iio_chan_spec const *chan, 293 306 int *val, int *val2, long mask) ··· 322 291 *val = data->dac_value; 323 292 return IIO_VAL_INT; 324 293 case IIO_CHAN_INFO_SCALE: 325 - ret = regulator_get_voltage(data->vdd_reg); 294 + if (data->ref_mode == MCP472X_REF_VDD) 295 + ret = regulator_get_voltage(data->vdd_reg); 296 + else 297 + ret = regulator_get_voltage(data->vref_reg); 298 + 326 299 if (ret < 0) 327 300 return ret; 328 301 ··· 370 335 struct mcp4725_data *data; 371 336 struct iio_dev *indio_dev; 372 337 struct mcp4725_platform_data *pdata = dev_get_platdata(&client->dev); 373 - u8 inbuf[3]; 338 + u8 inbuf[4]; 374 339 u8 pd; 340 + u8 ref; 375 341 int err; 376 342 377 343 if (!pdata) { ··· 386 350 data = iio_priv(indio_dev); 387 351 i2c_set_clientdata(client, indio_dev); 388 352 data->client = client; 353 + data->id = id->driver_data; 354 + 355 + if (data->id == MCP4725 && pdata->use_vref) { 356 + dev_err(&client->dev, 357 + "external reference is unavailable on MCP4725"); 358 + return -EINVAL; 359 + } 360 + 361 + if (!pdata->use_vref && pdata->vref_buffered) { 362 + dev_err(&client->dev, 363 + "buffering is unavailable on the internal reference"); 364 + return -EINVAL; 365 + } 366 + 367 + if (!pdata->use_vref) 368 + data->ref_mode = MCP472X_REF_VDD; 369 + else 370 + data->ref_mode = pdata->vref_buffered ? 371 + MCP472X_REF_VREF_BUFFERED : 372 + MCP472X_REF_VREF_UNBUFFERED; 389 373 390 374 data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); 391 375 if (IS_ERR(data->vdd_reg)) ··· 415 359 if (err) 416 360 return err; 417 361 362 + if (pdata->use_vref) { 363 + data->vref_reg = devm_regulator_get(&client->dev, "vref"); 364 + if (IS_ERR(data->vref_reg)) { 365 + err = PTR_ERR(data->vdd_reg); 366 + goto err_disable_vdd_reg; 367 + } 368 + 369 + err = regulator_enable(data->vref_reg); 370 + if (err) 371 + goto err_disable_vdd_reg; 372 + } 373 + 418 374 indio_dev->dev.parent = &client->dev; 419 375 indio_dev->name = id->name; 420 376 indio_dev->info = &mcp4725_info; ··· 434 366 indio_dev->num_channels = 1; 435 367 indio_dev->modes = INDIO_DIRECT_MODE; 436 368 437 - /* read current DAC value */ 438 - err = i2c_master_recv(client, inbuf, 3); 369 + /* read current DAC value and settings */ 370 + err = i2c_master_recv(client, inbuf, data->id == MCP4725 ? 3 : 4); 371 + 439 372 if (err < 0) { 440 373 dev_err(&client->dev, "failed to read DAC value"); 441 - goto err_disable_vdd_reg; 374 + goto err_disable_vref_reg; 442 375 } 443 376 pd = (inbuf[0] >> 1) & 0x3; 444 377 data->powerdown = pd > 0 ? true : false; 445 378 data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ 446 379 data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); 380 + if (data->id == MCP4726) 381 + ref = (inbuf[3] >> 3) & 0x3; 447 382 383 + if (data->id == MCP4726 && ref != data->ref_mode) { 384 + dev_info(&client->dev, 385 + "voltage reference mode differs (conf: %u, eeprom: %u), setting %u", 386 + data->ref_mode, ref, data->ref_mode); 387 + err = mcp4726_set_cfg(indio_dev); 388 + if (err < 0) 389 + goto err_disable_vref_reg; 390 + } 391 + 448 392 err = iio_device_register(indio_dev); 449 393 if (err) 450 - goto err_disable_vdd_reg; 394 + goto err_disable_vref_reg; 451 395 452 396 return 0; 453 397 398 + err_disable_vref_reg: 399 + if (data->vref_reg) 400 + regulator_disable(data->vref_reg); 454 401 455 402 err_disable_vdd_reg: 456 403 regulator_disable(data->vdd_reg); ··· 480 397 481 398 iio_device_unregister(indio_dev); 482 399 400 + if (data->vref_reg) 401 + regulator_disable(data->vref_reg); 483 402 regulator_disable(data->vdd_reg); 484 403 485 404 return 0;
+11
include/linux/iio/dac/mcp4725.h
··· 9 9 #ifndef IIO_DAC_MCP4725_H_ 10 10 #define IIO_DAC_MCP4725_H_ 11 11 12 + /** 13 + * struct mcp4725_platform_data - MCP4725/6 DAC specific data. 14 + * @use_vref: Whether an external reference voltage on Vref pin should be used. 15 + * Additional vref-supply must be specified when used. 16 + * @vref_buffered: Controls buffering of the external reference voltage. 17 + * 18 + * Vref related settings are available only on MCP4756. See 19 + * Documentation/devicetree/bindings/iio/dac/mcp4725.txt for more information. 20 + */ 12 21 struct mcp4725_platform_data { 22 + bool use_vref; 23 + bool vref_buffered; 13 24 }; 14 25 15 26 #endif /* IIO_DAC_MCP4725_H_ */