brintos

brintos / linux-shallow public Read only

0
0
Text · 11.2 KiB · 75b5498 Raw
474 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog4 * Converter5 *6 * Copyright 2011 Analog Devices Inc.7 */8 9#include <linux/interrupt.h>10#include <linux/fs.h>11#include <linux/device.h>12#include <linux/kernel.h>13#include <linux/spi/spi.h>14#include <linux/slab.h>15#include <linux/sysfs.h>16#include <linux/regulator/consumer.h>17#include <linux/module.h>18#include <linux/bitops.h>19 20#include <linux/iio/iio.h>21#include <linux/iio/sysfs.h>22#include <linux/iio/dac/ad5791.h>23 24#define AD5791_DAC_MASK			GENMASK(19, 0)25 26#define AD5791_CMD_READ			BIT(23)27#define AD5791_CMD_WRITE		028#define AD5791_ADDR(addr)		((addr) << 20)29 30/* Registers */31#define AD5791_ADDR_NOOP		032#define AD5791_ADDR_DAC0		133#define AD5791_ADDR_CTRL		234#define AD5791_ADDR_CLRCODE		335#define AD5791_ADDR_SW_CTRL		436 37/* Control Register */38#define AD5791_CTRL_RBUF		BIT(1)39#define AD5791_CTRL_OPGND		BIT(2)40#define AD5791_CTRL_DACTRI		BIT(3)41#define AD5791_CTRL_BIN2SC		BIT(4)42#define AD5791_CTRL_SDODIS		BIT(5)43#define AD5761_CTRL_LINCOMP(x)		((x) << 6)44 45#define AD5791_LINCOMP_0_10		046#define AD5791_LINCOMP_10_12		147#define AD5791_LINCOMP_12_16		248#define AD5791_LINCOMP_16_19		349#define AD5791_LINCOMP_19_20		1250 51#define AD5780_LINCOMP_0_10		052#define AD5780_LINCOMP_10_20		1253 54/* Software Control Register */55#define AD5791_SWCTRL_LDAC		BIT(0)56#define AD5791_SWCTRL_CLR		BIT(1)57#define AD5791_SWCTRL_RESET		BIT(2)58 59#define AD5791_DAC_PWRDN_6K		060#define AD5791_DAC_PWRDN_3STATE		161 62/**63 * struct ad5791_chip_info - chip specific information64 * @get_lin_comp:	function pointer to the device specific function65 */66 67struct ad5791_chip_info {68	int (*get_lin_comp)	(unsigned int span);69};70 71/**72 * struct ad5791_state - driver instance specific data73 * @spi:			spi_device74 * @reg_vdd:		positive supply regulator75 * @reg_vss:		negative supply regulator76 * @chip_info:		chip model specific constants77 * @vref_mv:		actual reference voltage used78 * @vref_neg_mv:	voltage of the negative supply79 * @ctrl:		control register cache80 * @pwr_down_mode:	current power down mode81 * @pwr_down:		true if device is powered down82 * @data:		spi transfer buffers83 */84struct ad5791_state {85	struct spi_device		*spi;86	struct regulator		*reg_vdd;87	struct regulator		*reg_vss;88	const struct ad5791_chip_info	*chip_info;89	unsigned short			vref_mv;90	unsigned int			vref_neg_mv;91	unsigned			ctrl;92	unsigned			pwr_down_mode;93	bool				pwr_down;94 95	union {96		__be32 d32;97		u8 d8[4];98	} data[3] __aligned(IIO_DMA_MINALIGN);99};100 101enum ad5791_supported_device_ids {102	ID_AD5760,103	ID_AD5780,104	ID_AD5781,105	ID_AD5791,106};107 108static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val)109{110	st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE |111			      AD5791_ADDR(addr) |112			      (val & AD5791_DAC_MASK));113 114	return spi_write(st->spi, &st->data[0].d8[1], 3);115}116 117static int ad5791_spi_read(struct ad5791_state *st, u8 addr, u32 *val)118{119	int ret;120	struct spi_transfer xfers[] = {121		{122			.tx_buf = &st->data[0].d8[1],123			.bits_per_word = 8,124			.len = 3,125			.cs_change = 1,126		}, {127			.tx_buf = &st->data[1].d8[1],128			.rx_buf = &st->data[2].d8[1],129			.bits_per_word = 8,130			.len = 3,131		},132	};133 134	st->data[0].d32 = cpu_to_be32(AD5791_CMD_READ |135			      AD5791_ADDR(addr));136	st->data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));137 138	ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));139 140	*val = be32_to_cpu(st->data[2].d32);141 142	return ret;143}144 145static const char * const ad5791_powerdown_modes[] = {146	"6kohm_to_gnd",147	"three_state",148};149 150static int ad5791_get_powerdown_mode(struct iio_dev *indio_dev,151	const struct iio_chan_spec *chan)152{153	struct ad5791_state *st = iio_priv(indio_dev);154 155	return st->pwr_down_mode;156}157 158static int ad5791_set_powerdown_mode(struct iio_dev *indio_dev,159	const struct iio_chan_spec *chan, unsigned int mode)160{161	struct ad5791_state *st = iio_priv(indio_dev);162 163	st->pwr_down_mode = mode;164 165	return 0;166}167 168static const struct iio_enum ad5791_powerdown_mode_enum = {169	.items = ad5791_powerdown_modes,170	.num_items = ARRAY_SIZE(ad5791_powerdown_modes),171	.get = ad5791_get_powerdown_mode,172	.set = ad5791_set_powerdown_mode,173};174 175static ssize_t ad5791_read_dac_powerdown(struct iio_dev *indio_dev,176	uintptr_t private, const struct iio_chan_spec *chan, char *buf)177{178	struct ad5791_state *st = iio_priv(indio_dev);179 180	return sysfs_emit(buf, "%d\n", st->pwr_down);181}182 183static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev,184	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,185	 size_t len)186{187	bool pwr_down;188	int ret;189	struct ad5791_state *st = iio_priv(indio_dev);190 191	ret = kstrtobool(buf, &pwr_down);192	if (ret)193		return ret;194 195	if (!pwr_down) {196		st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);197	} else {198		if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K)199			st->ctrl |= AD5791_CTRL_OPGND;200		else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE)201			st->ctrl |= AD5791_CTRL_DACTRI;202	}203	st->pwr_down = pwr_down;204 205	ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl);206 207	return ret ? ret : len;208}209 210static int ad5791_get_lin_comp(unsigned int span)211{212	if (span <= 10000)213		return AD5791_LINCOMP_0_10;214	else if (span <= 12000)215		return AD5791_LINCOMP_10_12;216	else if (span <= 16000)217		return AD5791_LINCOMP_12_16;218	else if (span <= 19000)219		return AD5791_LINCOMP_16_19;220	else221		return AD5791_LINCOMP_19_20;222}223 224static int ad5780_get_lin_comp(unsigned int span)225{226	if (span <= 10000)227		return AD5780_LINCOMP_0_10;228	else229		return AD5780_LINCOMP_10_20;230}231static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {232	[ID_AD5760] = {233		.get_lin_comp = ad5780_get_lin_comp,234	},235	[ID_AD5780] = {236		.get_lin_comp = ad5780_get_lin_comp,237	},238	[ID_AD5781] = {239		.get_lin_comp = ad5791_get_lin_comp,240	},241	[ID_AD5791] = {242		.get_lin_comp = ad5791_get_lin_comp,243	},244};245 246static int ad5791_read_raw(struct iio_dev *indio_dev,247			   struct iio_chan_spec const *chan,248			   int *val,249			   int *val2,250			   long m)251{252	struct ad5791_state *st = iio_priv(indio_dev);253	u64 val64;254	int ret;255 256	switch (m) {257	case IIO_CHAN_INFO_RAW:258		ret = ad5791_spi_read(st, chan->address, val);259		if (ret)260			return ret;261		*val &= AD5791_DAC_MASK;262		*val >>= chan->scan_type.shift;263		return IIO_VAL_INT;264	case IIO_CHAN_INFO_SCALE:265		*val = st->vref_mv;266		*val2 = (1 << chan->scan_type.realbits) - 1;267		return IIO_VAL_FRACTIONAL;268	case IIO_CHAN_INFO_OFFSET:269		val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits);270		do_div(val64, st->vref_mv);271		*val = -val64;272		return IIO_VAL_INT;273	default:274		return -EINVAL;275	}276 277};278 279static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {280	{281		.name = "powerdown",282		.shared = IIO_SHARED_BY_TYPE,283		.read = ad5791_read_dac_powerdown,284		.write = ad5791_write_dac_powerdown,285	},286	IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,287		 &ad5791_powerdown_mode_enum),288	IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5791_powerdown_mode_enum),289	{ },290};291 292#define AD5791_CHAN(bits, _shift) {			\293	.type = IIO_VOLTAGE,				\294	.output = 1,					\295	.indexed = 1,					\296	.address = AD5791_ADDR_DAC0,			\297	.channel = 0,					\298	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\299	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\300		BIT(IIO_CHAN_INFO_OFFSET),		\301	.scan_type = {					\302		.sign = 'u',				\303		.realbits = (bits),			\304		.storagebits = 24,			\305		.shift = (_shift),			\306	},						\307	.ext_info = ad5791_ext_info,			\308}309 310static const struct iio_chan_spec ad5791_channels[] = {311	[ID_AD5760] = AD5791_CHAN(16, 4),312	[ID_AD5780] = AD5791_CHAN(18, 2),313	[ID_AD5781] = AD5791_CHAN(18, 2),314	[ID_AD5791] = AD5791_CHAN(20, 0)315};316 317static int ad5791_write_raw(struct iio_dev *indio_dev,318			    struct iio_chan_spec const *chan,319			    int val,320			    int val2,321			    long mask)322{323	struct ad5791_state *st = iio_priv(indio_dev);324 325	switch (mask) {326	case IIO_CHAN_INFO_RAW:327		val &= GENMASK(chan->scan_type.realbits - 1, 0);328		val <<= chan->scan_type.shift;329 330		return ad5791_spi_write(st, chan->address, val);331 332	default:333		return -EINVAL;334	}335}336 337static const struct iio_info ad5791_info = {338	.read_raw = &ad5791_read_raw,339	.write_raw = &ad5791_write_raw,340};341 342static int ad5791_probe(struct spi_device *spi)343{344	struct ad5791_platform_data *pdata = spi->dev.platform_data;345	struct iio_dev *indio_dev;346	struct ad5791_state *st;347	int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;348	bool use_rbuf_gain2;349 350	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));351	if (!indio_dev)352		return -ENOMEM;353	st = iio_priv(indio_dev);354	st->reg_vdd = devm_regulator_get(&spi->dev, "vdd");355	if (!IS_ERR(st->reg_vdd)) {356		ret = regulator_enable(st->reg_vdd);357		if (ret)358			return ret;359 360		ret = regulator_get_voltage(st->reg_vdd);361		if (ret < 0)362			goto error_disable_reg_pos;363 364		pos_voltage_uv = ret;365	}366 367	st->reg_vss = devm_regulator_get(&spi->dev, "vss");368	if (!IS_ERR(st->reg_vss)) {369		ret = regulator_enable(st->reg_vss);370		if (ret)371			goto error_disable_reg_pos;372 373		ret = regulator_get_voltage(st->reg_vss);374		if (ret < 0)375			goto error_disable_reg_neg;376 377		neg_voltage_uv = ret;378	}379 380	st->pwr_down = true;381	st->spi = spi;382 383	if (pdata)384		use_rbuf_gain2 = pdata->use_rbuf_gain2;385	else386		use_rbuf_gain2 = device_property_read_bool(&spi->dev,387							   "adi,rbuf-gain2-en");388 389	if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {390		st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;391		st->vref_neg_mv = neg_voltage_uv / 1000;392	} else if (pdata) {393		st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv;394		st->vref_neg_mv = pdata->vref_neg_mv;395	} else {396		dev_warn(&spi->dev, "reference voltage unspecified\n");397	}398 399	ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);400	if (ret)401		goto error_disable_reg_neg;402 403	st->chip_info =	&ad5791_chip_info_tbl[spi_get_device_id(spi)404					      ->driver_data];405 406 407	st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))408		  | (use_rbuf_gain2 ? 0 : AD5791_CTRL_RBUF) |409		  AD5791_CTRL_BIN2SC;410 411	ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl |412		AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);413	if (ret)414		goto error_disable_reg_neg;415 416	spi_set_drvdata(spi, indio_dev);417	indio_dev->info = &ad5791_info;418	indio_dev->modes = INDIO_DIRECT_MODE;419	indio_dev->channels420		= &ad5791_channels[spi_get_device_id(spi)->driver_data];421	indio_dev->num_channels = 1;422	indio_dev->name = spi_get_device_id(st->spi)->name;423	ret = iio_device_register(indio_dev);424	if (ret)425		goto error_disable_reg_neg;426 427	return 0;428 429error_disable_reg_neg:430	if (!IS_ERR(st->reg_vss))431		regulator_disable(st->reg_vss);432error_disable_reg_pos:433	if (!IS_ERR(st->reg_vdd))434		regulator_disable(st->reg_vdd);435	return ret;436}437 438static void ad5791_remove(struct spi_device *spi)439{440	struct iio_dev *indio_dev = spi_get_drvdata(spi);441	struct ad5791_state *st = iio_priv(indio_dev);442 443	iio_device_unregister(indio_dev);444	if (!IS_ERR(st->reg_vdd))445		regulator_disable(st->reg_vdd);446 447	if (!IS_ERR(st->reg_vss))448		regulator_disable(st->reg_vss);449}450 451static const struct spi_device_id ad5791_id[] = {452	{"ad5760", ID_AD5760},453	{"ad5780", ID_AD5780},454	{"ad5781", ID_AD5781},455	{"ad5790", ID_AD5791},456	{"ad5791", ID_AD5791},457	{}458};459MODULE_DEVICE_TABLE(spi, ad5791_id);460 461static struct spi_driver ad5791_driver = {462	.driver = {463		   .name = "ad5791",464		   },465	.probe = ad5791_probe,466	.remove = ad5791_remove,467	.id_table = ad5791_id,468};469module_spi_driver(ad5791_driver);470 471MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");472MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");473MODULE_LICENSE("GPL v2");474