drivers/iio/dac/mcp4728.c

Source file repositories/reference/linux-study-clean/drivers/iio/dac/mcp4728.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/dac/mcp4728.c
Extension
.c
Size
15244 bytes
Lines
600
Domain
Driver Families
Bucket
drivers/iio
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mcp4728_channel_data {
	enum vref_mode ref_mode;
	enum iio_powerdown_mode pd_mode;
	enum gain_mode g_mode;
	u16 dac_value;
};

/* MCP4728 Full Scale Ranges
 * the device available ranges are
 * - VREF = VDD				FSR = from 0.0V to VDD
 * - VREF = Internal	Gain = 1	FSR = from 0.0V to VREF
 * - VREF = Internal	Gain = 2	FSR = from 0.0V to 2*VREF
 */
enum mcp4728_scale {
	MCP4728_SCALE_VDD,
	MCP4728_SCALE_VINT_NO_GAIN,
	MCP4728_SCALE_VINT_GAIN_X2,
	MCP4728_N_SCALES
};

struct mcp4728_data {
	struct i2c_client *client;
	bool powerdown;
	int scales_avail[MCP4728_N_SCALES * 2];
	struct mcp4728_channel_data chdata[MCP4728_N_CHANNELS];
};

#define MCP4728_CHAN(chan) {						\
	.type = IIO_VOLTAGE,						\
	.output = 1,							\
	.indexed = 1,							\
	.channel = chan,						\
	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)	|		\
			      BIT(IIO_CHAN_INFO_SCALE),			\
	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),	\
	.ext_info = mcp4728_ext_info,					\
}

static int mcp4728_suspend(struct device *dev);
static int mcp4728_resume(struct device *dev);

static ssize_t mcp4728_store_eeprom(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t len)
{
	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
	struct mcp4728_data *data = iio_priv(indio_dev);
	u8 outbuf[MCP4728_WRITE_EEPROM_LEN];
	int tries = 20;
	u8 inbuf[3];
	bool state;
	int ret;
	unsigned int i;

	ret = kstrtobool(buf, &state);
	if (ret < 0)
		return ret;

	if (!state)
		return 0;

	outbuf[0] = FIELD_PREP(MCP4728_CMD_MASK, MCP4728_SW_CMD);

	for (i = 0; i < MCP4728_N_CHANNELS; i++) {
		struct mcp4728_channel_data *ch = &data->chdata[i];
		int offset			= 1 + i * 2;

		outbuf[offset] = FIELD_PREP(MCP4728_VREF_MASK, ch->ref_mode);

		if (data->powerdown) {
			u8 mcp4728_pd_mode = ch->pd_mode + 1;

			outbuf[offset] |= FIELD_PREP(MCP4728_PDMODE_MASK,
						     mcp4728_pd_mode);
		}

		outbuf[offset] |= FIELD_PREP(MCP4728_GAIN_MASK, ch->g_mode);
		outbuf[offset] |=
			FIELD_PREP(MCP4728_DAC_H_MASK, ch->dac_value >> 8);
		outbuf[offset + 1] =
			FIELD_PREP(MCP4728_DAC_L_MASK, ch->dac_value);
	}

	ret = i2c_master_send(data->client, outbuf, MCP4728_WRITE_EEPROM_LEN);
	if (ret < 0)
		return ret;
	else if (ret != MCP4728_WRITE_EEPROM_LEN)
		return -EIO;

	/* wait RDY signal for write complete, takes up to 50ms */

Annotation

Implementation Notes