brintos

brintos / linux-shallow public Read only

0
0
Text · 14.9 KiB · 192175d Raw
600 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Support for Microchip MCP47284 *5 * Copyright (C) 2023 Andrea Collamati <andrea.collamati@gmail.com>6 *7 * Based on mcp4725 by Peter Meerwald <pmeerw@pmeerw.net>8 *9 * Driver for the Microchip I2C 12-bit digital-to-analog quad channels10 * converter (DAC).11 *12 * (7-bit I2C slave address 0x60, the three LSBs can be configured in13 * hardware)14 */15 16#include <linux/bitfield.h>17#include <linux/delay.h>18#include <linux/err.h>19#include <linux/i2c.h>20#include <linux/iio/iio.h>21#include <linux/iio/sysfs.h>22#include <linux/module.h>23#include <linux/mod_devicetable.h>24#include <linux/property.h>25#include <linux/regulator/consumer.h>26 27#define MCP4728_RESOLUTION	  1228#define MCP4728_N_CHANNELS	  429 30#define MCP4728_CMD_MASK	  GENMASK(7, 3)31#define MCP4728_CHSEL_MASK	  GENMASK(2, 1)32#define MCP4728_UDAC_MASK	  BIT(0)33 34#define MCP4728_VREF_MASK	  BIT(7)35#define MCP4728_PDMODE_MASK	  GENMASK(6, 5)36#define MCP4728_GAIN_MASK	  BIT(4)37 38#define MCP4728_DAC_H_MASK	  GENMASK(3, 0)39#define MCP4728_DAC_L_MASK	  GENMASK(7, 0)40 41#define MCP4728_RDY_MASK	  BIT(7)42 43#define MCP4728_MW_CMD		  0x08 /* Multiwrite Command */44#define MCP4728_SW_CMD		  0x0A /* Sequential Write Command with EEPROM */45 46#define MCP4728_READ_RESPONSE_LEN (MCP4728_N_CHANNELS * 3 * 2)47#define MCP4728_WRITE_EEPROM_LEN  (1 + MCP4728_N_CHANNELS * 2)48 49enum vref_mode {50	MCP4728_VREF_EXTERNAL_VDD    = 0,51	MCP4728_VREF_INTERNAL_2048mV = 1,52};53 54enum gain_mode {55	MCP4728_GAIN_X1 = 0,56	MCP4728_GAIN_X2 = 1,57};58 59enum iio_powerdown_mode {60	MCP4728_IIO_1K,61	MCP4728_IIO_100K,62	MCP4728_IIO_500K,63};64 65struct mcp4728_channel_data {66	enum vref_mode ref_mode;67	enum iio_powerdown_mode pd_mode;68	enum gain_mode g_mode;69	u16 dac_value;70};71 72/* MCP4728 Full Scale Ranges73 * the device available ranges are74 * - VREF = VDD				FSR = from 0.0V to VDD75 * - VREF = Internal	Gain = 1	FSR = from 0.0V to VREF76 * - VREF = Internal	Gain = 2	FSR = from 0.0V to 2*VREF77 */78enum mcp4728_scale {79	MCP4728_SCALE_VDD,80	MCP4728_SCALE_VINT_NO_GAIN,81	MCP4728_SCALE_VINT_GAIN_X2,82	MCP4728_N_SCALES83};84 85struct mcp4728_data {86	struct i2c_client *client;87	bool powerdown;88	int scales_avail[MCP4728_N_SCALES * 2];89	struct mcp4728_channel_data chdata[MCP4728_N_CHANNELS];90};91 92#define MCP4728_CHAN(chan) {						\93	.type = IIO_VOLTAGE,						\94	.output = 1,							\95	.indexed = 1,							\96	.channel = chan,						\97	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)	|		\98			      BIT(IIO_CHAN_INFO_SCALE),			\99	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),	\100	.ext_info = mcp4728_ext_info,					\101}102 103static int mcp4728_suspend(struct device *dev);104static int mcp4728_resume(struct device *dev);105 106static ssize_t mcp4728_store_eeprom(struct device *dev,107				    struct device_attribute *attr,108				    const char *buf, size_t len)109{110	struct iio_dev *indio_dev = dev_to_iio_dev(dev);111	struct mcp4728_data *data = iio_priv(indio_dev);112	u8 outbuf[MCP4728_WRITE_EEPROM_LEN];113	int tries = 20;114	u8 inbuf[3];115	bool state;116	int ret;117	unsigned int i;118 119	ret = kstrtobool(buf, &state);120	if (ret < 0)121		return ret;122 123	if (!state)124		return 0;125 126	outbuf[0] = FIELD_PREP(MCP4728_CMD_MASK, MCP4728_SW_CMD);127 128	for (i = 0; i < MCP4728_N_CHANNELS; i++) {129		struct mcp4728_channel_data *ch = &data->chdata[i];130		int offset			= 1 + i * 2;131 132		outbuf[offset] = FIELD_PREP(MCP4728_VREF_MASK, ch->ref_mode);133 134		if (data->powerdown) {135			u8 mcp4728_pd_mode = ch->pd_mode + 1;136 137			outbuf[offset] |= FIELD_PREP(MCP4728_PDMODE_MASK,138						     mcp4728_pd_mode);139		}140 141		outbuf[offset] |= FIELD_PREP(MCP4728_GAIN_MASK, ch->g_mode);142		outbuf[offset] |=143			FIELD_PREP(MCP4728_DAC_H_MASK, ch->dac_value >> 8);144		outbuf[offset + 1] =145			FIELD_PREP(MCP4728_DAC_L_MASK, ch->dac_value);146	}147 148	ret = i2c_master_send(data->client, outbuf, MCP4728_WRITE_EEPROM_LEN);149	if (ret < 0)150		return ret;151	else if (ret != MCP4728_WRITE_EEPROM_LEN)152		return -EIO;153 154	/* wait RDY signal for write complete, takes up to 50ms */155	while (tries--) {156		msleep(20);157		ret = i2c_master_recv(data->client, inbuf, 3);158		if (ret < 0)159			return ret;160		else if (ret != 3)161			return -EIO;162 163		if (FIELD_GET(MCP4728_RDY_MASK, inbuf[0]))164			break;165	}166 167	if (tries < 0) {168		dev_err(&data->client->dev, "%s failed, incomplete\n",169			__func__);170		return -EIO;171	}172	return len;173}174 175static IIO_DEVICE_ATTR(store_eeprom, 0200, NULL, mcp4728_store_eeprom, 0);176 177static struct attribute *mcp4728_attributes[] = {178	&iio_dev_attr_store_eeprom.dev_attr.attr,179	NULL,180};181 182static const struct attribute_group mcp4728_attribute_group = {183	.attrs = mcp4728_attributes,184};185 186static int mcp4728_program_channel_cfg(int channel, struct iio_dev *indio_dev)187{188	struct mcp4728_data *data	= iio_priv(indio_dev);189	struct mcp4728_channel_data *ch = &data->chdata[channel];190	u8 outbuf[3];191	int ret;192 193	outbuf[0] = FIELD_PREP(MCP4728_CMD_MASK, MCP4728_MW_CMD);194	outbuf[0] |= FIELD_PREP(MCP4728_CHSEL_MASK, channel);195	outbuf[0] |= FIELD_PREP(MCP4728_UDAC_MASK, 0);196 197	outbuf[1] = FIELD_PREP(MCP4728_VREF_MASK, ch->ref_mode);198 199	if (data->powerdown)200		outbuf[1] |= FIELD_PREP(MCP4728_PDMODE_MASK, ch->pd_mode + 1);201 202	outbuf[1] |= FIELD_PREP(MCP4728_GAIN_MASK, ch->g_mode);203	outbuf[1] |= FIELD_PREP(MCP4728_DAC_H_MASK, ch->dac_value >> 8);204	outbuf[2] = FIELD_PREP(MCP4728_DAC_L_MASK, ch->dac_value);205 206	ret = i2c_master_send(data->client, outbuf, 3);207	if (ret < 0)208		return ret;209	else if (ret != 3)210		return -EIO;211 212	return 0;213}214 215static const char *const mcp4728_powerdown_modes[] = { "1kohm_to_gnd",216						       "100kohm_to_gnd",217						       "500kohm_to_gnd" };218 219static int mcp4728_get_powerdown_mode(struct iio_dev *indio_dev,220				      const struct iio_chan_spec *chan)221{222	struct mcp4728_data *data = iio_priv(indio_dev);223 224	return data->chdata[chan->channel].pd_mode;225}226 227static int mcp4728_set_powerdown_mode(struct iio_dev *indio_dev,228				      const struct iio_chan_spec *chan,229				      unsigned int mode)230{231	struct mcp4728_data *data = iio_priv(indio_dev);232 233	data->chdata[chan->channel].pd_mode = mode;234 235	return 0;236}237 238static ssize_t mcp4728_read_powerdown(struct iio_dev *indio_dev,239				      uintptr_t private,240				      const struct iio_chan_spec *chan,241				      char *buf)242{243	struct mcp4728_data *data = iio_priv(indio_dev);244 245	return sysfs_emit(buf, "%d\n", data->powerdown);246}247 248static ssize_t mcp4728_write_powerdown(struct iio_dev *indio_dev,249				       uintptr_t private,250				       const struct iio_chan_spec *chan,251				       const char *buf, size_t len)252{253	struct mcp4728_data *data = iio_priv(indio_dev);254	bool state;255	int ret;256 257	ret = kstrtobool(buf, &state);258	if (ret)259		return ret;260 261	if (state)262		ret = mcp4728_suspend(&data->client->dev);263	else264		ret = mcp4728_resume(&data->client->dev);265 266	if (ret < 0)267		return ret;268 269	return len;270}271 272static const struct iio_enum mcp4728_powerdown_mode_enum = {273	.items	   = mcp4728_powerdown_modes,274	.num_items = ARRAY_SIZE(mcp4728_powerdown_modes),275	.get	   = mcp4728_get_powerdown_mode,276	.set	   = mcp4728_set_powerdown_mode,277};278 279static const struct iio_chan_spec_ext_info mcp4728_ext_info[] = {280	{281		.name	= "powerdown",282		.read	= mcp4728_read_powerdown,283		.write	= mcp4728_write_powerdown,284		.shared = IIO_SEPARATE,285	},286	IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp4728_powerdown_mode_enum),287	IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,288			   &mcp4728_powerdown_mode_enum),289	{},290};291 292static const struct iio_chan_spec mcp4728_channels[MCP4728_N_CHANNELS] = {293	MCP4728_CHAN(0),294	MCP4728_CHAN(1),295	MCP4728_CHAN(2),296	MCP4728_CHAN(3),297};298 299static void mcp4728_get_scale_avail(enum mcp4728_scale scale,300				    struct mcp4728_data *data, int *val,301				    int *val2)302{303	*val  = data->scales_avail[scale * 2];304	*val2 = data->scales_avail[scale * 2 + 1];305}306 307static void mcp4728_get_scale(int channel, struct mcp4728_data *data, int *val,308			      int *val2)309{310	int ref_mode = data->chdata[channel].ref_mode;311	int g_mode   = data->chdata[channel].g_mode;312 313	if (ref_mode == MCP4728_VREF_EXTERNAL_VDD) {314		mcp4728_get_scale_avail(MCP4728_SCALE_VDD, data, val, val2);315	} else {316		if (g_mode == MCP4728_GAIN_X1) {317			mcp4728_get_scale_avail(MCP4728_SCALE_VINT_NO_GAIN,318						data, val, val2);319		} else {320			mcp4728_get_scale_avail(MCP4728_SCALE_VINT_GAIN_X2,321						data, val, val2);322		}323	}324}325 326static int mcp4728_find_matching_scale(struct mcp4728_data *data, int val,327				       int val2)328{329	for (int i = 0; i < MCP4728_N_SCALES; i++) {330		if (data->scales_avail[i * 2] == val &&331		    data->scales_avail[i * 2 + 1] == val2)332			return i;333	}334	return -EINVAL;335}336 337static int mcp4728_set_scale(int channel, struct mcp4728_data *data, int val,338			     int val2)339{340	int scale = mcp4728_find_matching_scale(data, val, val2);341 342	if (scale < 0)343		return scale;344 345	switch (scale) {346	case MCP4728_SCALE_VDD:347		data->chdata[channel].ref_mode = MCP4728_VREF_EXTERNAL_VDD;348		return 0;349	case MCP4728_SCALE_VINT_NO_GAIN:350		data->chdata[channel].ref_mode = MCP4728_VREF_INTERNAL_2048mV;351		data->chdata[channel].g_mode   = MCP4728_GAIN_X1;352		return 0;353	case MCP4728_SCALE_VINT_GAIN_X2:354		data->chdata[channel].ref_mode = MCP4728_VREF_INTERNAL_2048mV;355		data->chdata[channel].g_mode   = MCP4728_GAIN_X2;356		return 0;357	default:358		return -EINVAL;359	}360}361 362static int mcp4728_read_raw(struct iio_dev *indio_dev,363			    struct iio_chan_spec const *chan, int *val,364			    int *val2, long mask)365{366	struct mcp4728_data *data = iio_priv(indio_dev);367 368	switch (mask) {369	case IIO_CHAN_INFO_RAW:370		*val = data->chdata[chan->channel].dac_value;371		return IIO_VAL_INT;372	case IIO_CHAN_INFO_SCALE:373		mcp4728_get_scale(chan->channel, data, val, val2);374		return IIO_VAL_INT_PLUS_MICRO;375	}376	return -EINVAL;377}378 379static int mcp4728_write_raw(struct iio_dev *indio_dev,380			     struct iio_chan_spec const *chan, int val,381			     int val2, long mask)382{383	struct mcp4728_data *data = iio_priv(indio_dev);384	int ret;385 386	switch (mask) {387	case IIO_CHAN_INFO_RAW:388		if (val < 0 || val > GENMASK(MCP4728_RESOLUTION - 1, 0))389			return -EINVAL;390		data->chdata[chan->channel].dac_value = val;391		return mcp4728_program_channel_cfg(chan->channel, indio_dev);392	case IIO_CHAN_INFO_SCALE:393		ret = mcp4728_set_scale(chan->channel, data, val, val2);394		if (ret)395			return ret;396 397		return mcp4728_program_channel_cfg(chan->channel, indio_dev);398	default:399		return -EINVAL;400	}401}402 403static void mcp4728_init_scale_avail(enum mcp4728_scale scale, int vref_mv,404				     struct mcp4728_data *data)405{406	s64 tmp;407	int value_micro;408	int value_int;409 410	tmp	  = (s64)vref_mv * 1000000LL >> MCP4728_RESOLUTION;411	value_int = div_s64_rem(tmp, 1000000LL, &value_micro);412 413	data->scales_avail[scale * 2]	  = value_int;414	data->scales_avail[scale * 2 + 1] = value_micro;415}416 417static int mcp4728_init_scales_avail(struct mcp4728_data *data, int vdd_mv)418{419	mcp4728_init_scale_avail(MCP4728_SCALE_VDD, vdd_mv, data);420	mcp4728_init_scale_avail(MCP4728_SCALE_VINT_NO_GAIN, 2048, data);421	mcp4728_init_scale_avail(MCP4728_SCALE_VINT_GAIN_X2, 4096, data);422 423	return 0;424}425 426static int mcp4728_read_avail(struct iio_dev *indio_dev,427			      struct iio_chan_spec const *chan,428			      const int **vals, int *type, int *length,429			      long info)430{431	struct mcp4728_data *data = iio_priv(indio_dev);432 433	switch (info) {434	case IIO_CHAN_INFO_SCALE:435		*type = IIO_VAL_INT_PLUS_MICRO;436 437		switch (chan->type) {438		case IIO_VOLTAGE:439			*vals	= data->scales_avail;440			*length = MCP4728_N_SCALES * 2;441			return IIO_AVAIL_LIST;442		default:443			return -EINVAL;444		}445	default:446		return -EINVAL;447	}448}449 450static const struct iio_info mcp4728_info = {451	.read_raw   = mcp4728_read_raw,452	.write_raw  = mcp4728_write_raw,453	.read_avail = &mcp4728_read_avail,454	.attrs	    = &mcp4728_attribute_group,455};456 457static int mcp4728_suspend(struct device *dev)458{459	struct iio_dev *indio_dev = dev_get_drvdata(dev);460	struct mcp4728_data *data = iio_priv(indio_dev);461	unsigned int i;462 463	data->powerdown = true;464 465	for (i = 0; i < MCP4728_N_CHANNELS; i++) {466		int err = mcp4728_program_channel_cfg(i, indio_dev);467 468		if (err)469			return err;470	}471	return 0;472}473 474static int mcp4728_resume(struct device *dev)475{476	struct iio_dev *indio_dev = dev_get_drvdata(dev);477	struct mcp4728_data *data = iio_priv(indio_dev);478	int err			  = 0;479	unsigned int i;480 481	data->powerdown = false;482 483	for (i = 0; i < MCP4728_N_CHANNELS; i++) {484		int ret = mcp4728_program_channel_cfg(i, indio_dev);485 486		if (ret)487			err = ret;488	}489	return err;490}491 492static DEFINE_SIMPLE_DEV_PM_OPS(mcp4728_pm_ops, mcp4728_suspend,493				mcp4728_resume);494 495static int mcp4728_init_channels_data(struct mcp4728_data *data)496{497	u8 inbuf[MCP4728_READ_RESPONSE_LEN];498	int ret;499	unsigned int i;500 501	ret = i2c_master_recv(data->client, inbuf, MCP4728_READ_RESPONSE_LEN);502	if (ret < 0) {503		return dev_err_probe(&data->client->dev, ret,504				     "failed to read mcp4728 conf.\n");505	} else if (ret != MCP4728_READ_RESPONSE_LEN) {506		return dev_err_probe(&data->client->dev, -EIO,507			"failed to read mcp4728 conf. Wrong Response Len ret=%d\n",508			ret);509	}510 511	for (i = 0; i < MCP4728_N_CHANNELS; i++) {512		struct mcp4728_channel_data *ch = &data->chdata[i];513		u8 r2				= inbuf[i * 6 + 1];514		u8 r3				= inbuf[i * 6 + 2];515 516		ch->dac_value = FIELD_GET(MCP4728_DAC_H_MASK, r2) << 8 |517				FIELD_GET(MCP4728_DAC_L_MASK, r3);518		ch->ref_mode = FIELD_GET(MCP4728_VREF_MASK, r2);519		ch->pd_mode  = FIELD_GET(MCP4728_PDMODE_MASK, r2);520		ch->g_mode   = FIELD_GET(MCP4728_GAIN_MASK, r2);521	}522 523	return 0;524}525 526static int mcp4728_probe(struct i2c_client *client)527{528	const struct i2c_device_id *id = i2c_client_get_device_id(client);529	struct mcp4728_data *data;530	struct iio_dev *indio_dev;531	int ret, vdd_mv;532 533	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));534	if (!indio_dev)535		return -ENOMEM;536 537	data = iio_priv(indio_dev);538	i2c_set_clientdata(client, indio_dev);539	data->client = client;540 541	ret = devm_regulator_get_enable_read_voltage(&client->dev, "vdd");542	if (ret < 0)543		return ret;544 545	vdd_mv = ret / 1000;546 547	/*548	 * MCP4728 has internal EEPROM that save each channel boot549	 * configuration. It means that device configuration is unknown to the550	 * driver at kernel boot. mcp4728_init_channels_data() reads back DAC551	 * settings and stores them in data structure.552	 */553	ret = mcp4728_init_channels_data(data);554	if (ret) {555		return dev_err_probe(&client->dev, ret,556			"failed to read mcp4728 current configuration\n");557	}558 559	ret = mcp4728_init_scales_avail(data, vdd_mv);560	if (ret) {561		return dev_err_probe(&client->dev, ret,562				     "failed to init scales\n");563	}564 565	indio_dev->name		= id->name;566	indio_dev->info		= &mcp4728_info;567	indio_dev->channels	= mcp4728_channels;568	indio_dev->num_channels = MCP4728_N_CHANNELS;569	indio_dev->modes	= INDIO_DIRECT_MODE;570 571	return devm_iio_device_register(&client->dev, indio_dev);572}573 574static const struct i2c_device_id mcp4728_id[] = {575	{ "mcp4728" },576	{}577};578MODULE_DEVICE_TABLE(i2c, mcp4728_id);579 580static const struct of_device_id mcp4728_of_match[] = {581	{ .compatible = "microchip,mcp4728" },582	{}583};584MODULE_DEVICE_TABLE(of, mcp4728_of_match);585 586static struct i2c_driver mcp4728_driver = {587	.driver = {588		.name = "mcp4728",589		.of_match_table = mcp4728_of_match,590		.pm = pm_sleep_ptr(&mcp4728_pm_ops),591	},592	.probe = mcp4728_probe,593	.id_table = mcp4728_id,594};595module_i2c_driver(mcp4728_driver);596 597MODULE_AUTHOR("Andrea Collamati <andrea.collamati@gmail.com>");598MODULE_DESCRIPTION("MCP4728 12-bit DAC");599MODULE_LICENSE("GPL");600