brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · 2758fc8 Raw
248 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for Linear Technology LTC1665/LTC1660, 8 channels DAC4 *5 * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>6 */7#include <linux/bitops.h>8#include <linux/iio/iio.h>9#include <linux/iio/sysfs.h>10#include <linux/init.h>11#include <linux/module.h>12#include <linux/regulator/consumer.h>13#include <linux/regmap.h>14#include <linux/spi/spi.h>15 16#define LTC1660_REG_WAKE	0x017#define LTC1660_REG_DAC_A	0x118#define LTC1660_REG_DAC_B	0x219#define LTC1660_REG_DAC_C	0x320#define LTC1660_REG_DAC_D	0x421#define LTC1660_REG_DAC_E	0x522#define LTC1660_REG_DAC_F	0x623#define LTC1660_REG_DAC_G	0x724#define LTC1660_REG_DAC_H	0x825#define LTC1660_REG_SLEEP	0xe26 27#define LTC1660_NUM_CHANNELS	828 29static const struct regmap_config ltc1660_regmap_config = {30	.reg_bits = 4,31	.val_bits = 12,32};33 34enum ltc1660_supported_device_ids {35	ID_LTC1660,36	ID_LTC1665,37};38 39struct ltc1660_priv {40	struct spi_device *spi;41	struct regmap *regmap;42	struct regulator *vref_reg;43	unsigned int value[LTC1660_NUM_CHANNELS];44	unsigned int vref_mv;45};46 47static int ltc1660_read_raw(struct iio_dev *indio_dev,48		struct iio_chan_spec const *chan,49		int *val,50		int *val2,51		long mask)52{53	struct ltc1660_priv *priv = iio_priv(indio_dev);54 55	switch (mask) {56	case IIO_CHAN_INFO_RAW:57		*val = priv->value[chan->channel];58		return IIO_VAL_INT;59	case IIO_CHAN_INFO_SCALE:60		*val = regulator_get_voltage(priv->vref_reg);61		if (*val < 0) {62			dev_err(&priv->spi->dev, "failed to read vref regulator: %d\n",63					*val);64			return *val;65		}66 67		/* Convert to mV */68		*val /= 1000;69		*val2 = chan->scan_type.realbits;70		return IIO_VAL_FRACTIONAL_LOG2;71	default:72		return -EINVAL;73	}74}75 76static int ltc1660_write_raw(struct iio_dev *indio_dev,77		struct iio_chan_spec const *chan,78		int val,79		int val2,80		long mask)81{82	struct ltc1660_priv *priv = iio_priv(indio_dev);83	int ret;84 85	switch (mask) {86	case IIO_CHAN_INFO_RAW:87		if (val2 != 0)88			return -EINVAL;89 90		if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))91			return -EINVAL;92 93		ret = regmap_write(priv->regmap, chan->channel,94					(val << chan->scan_type.shift));95		if (!ret)96			priv->value[chan->channel] = val;97 98		return ret;99	default:100		return -EINVAL;101	}102}103 104#define LTC1660_CHAN(chan, bits) {			\105	.type = IIO_VOLTAGE,				\106	.indexed = 1,					\107	.output = 1,					\108	.channel = chan,				\109	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\110	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\111	.scan_type = {					\112		.sign = 'u',				\113		.realbits = (bits),			\114		.storagebits = 16,			\115		.shift = 12 - (bits),			\116	},						\117}118 119#define  LTC1660_OCTAL_CHANNELS(bits) {			\120		LTC1660_CHAN(LTC1660_REG_DAC_A, bits),	\121		LTC1660_CHAN(LTC1660_REG_DAC_B, bits),	\122		LTC1660_CHAN(LTC1660_REG_DAC_C, bits),	\123		LTC1660_CHAN(LTC1660_REG_DAC_D, bits),	\124		LTC1660_CHAN(LTC1660_REG_DAC_E, bits),	\125		LTC1660_CHAN(LTC1660_REG_DAC_F, bits),	\126		LTC1660_CHAN(LTC1660_REG_DAC_G, bits),	\127		LTC1660_CHAN(LTC1660_REG_DAC_H, bits),	\128}129 130static const struct iio_chan_spec ltc1660_channels[][LTC1660_NUM_CHANNELS] = {131	[ID_LTC1660] = LTC1660_OCTAL_CHANNELS(10),132	[ID_LTC1665] = LTC1660_OCTAL_CHANNELS(8),133};134 135static const struct iio_info ltc1660_info = {136	.read_raw = &ltc1660_read_raw,137	.write_raw = &ltc1660_write_raw,138};139 140static int ltc1660_suspend(struct device *dev)141{142	struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(143						to_spi_device(dev)));144	return regmap_write(priv->regmap, LTC1660_REG_SLEEP, 0x00);145}146 147static int ltc1660_resume(struct device *dev)148{149	struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(150						to_spi_device(dev)));151	return regmap_write(priv->regmap, LTC1660_REG_WAKE, 0x00);152}153static DEFINE_SIMPLE_DEV_PM_OPS(ltc1660_pm_ops, ltc1660_suspend,154				ltc1660_resume);155 156static int ltc1660_probe(struct spi_device *spi)157{158	struct iio_dev *indio_dev;159	struct ltc1660_priv *priv;160	const struct spi_device_id *id = spi_get_device_id(spi);161	int ret;162 163	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));164	if (indio_dev == NULL)165		return -ENOMEM;166 167	priv = iio_priv(indio_dev);168	priv->regmap = devm_regmap_init_spi(spi, &ltc1660_regmap_config);169	if (IS_ERR(priv->regmap)) {170		dev_err(&spi->dev, "failed to register spi regmap %ld\n",171			PTR_ERR(priv->regmap));172		return PTR_ERR(priv->regmap);173	}174 175	priv->vref_reg = devm_regulator_get(&spi->dev, "vref");176	if (IS_ERR(priv->vref_reg))177		return dev_err_probe(&spi->dev, PTR_ERR(priv->vref_reg),178				     "vref regulator not specified\n");179 180	ret = regulator_enable(priv->vref_reg);181	if (ret) {182		dev_err(&spi->dev, "failed to enable vref regulator: %d\n",183				ret);184		return ret;185	}186 187	priv->spi = spi;188	spi_set_drvdata(spi, indio_dev);189	indio_dev->info = &ltc1660_info;190	indio_dev->modes = INDIO_DIRECT_MODE;191	indio_dev->channels = ltc1660_channels[id->driver_data];192	indio_dev->num_channels = LTC1660_NUM_CHANNELS;193	indio_dev->name = id->name;194 195	ret = iio_device_register(indio_dev);196	if (ret) {197		dev_err(&spi->dev, "failed to register iio device: %d\n",198				ret);199		goto error_disable_reg;200	}201 202	return 0;203 204error_disable_reg:205	regulator_disable(priv->vref_reg);206 207	return ret;208}209 210static void ltc1660_remove(struct spi_device *spi)211{212	struct iio_dev *indio_dev = spi_get_drvdata(spi);213	struct ltc1660_priv *priv = iio_priv(indio_dev);214 215	iio_device_unregister(indio_dev);216	regulator_disable(priv->vref_reg);217}218 219static const struct of_device_id ltc1660_dt_ids[] = {220	{ .compatible = "lltc,ltc1660", .data = (void *)ID_LTC1660 },221	{ .compatible = "lltc,ltc1665", .data = (void *)ID_LTC1665 },222	{ /* sentinel */ }223};224MODULE_DEVICE_TABLE(of, ltc1660_dt_ids);225 226static const struct spi_device_id ltc1660_id[] = {227	{"ltc1660", ID_LTC1660},228	{"ltc1665", ID_LTC1665},229	{ /* sentinel */ }230};231MODULE_DEVICE_TABLE(spi, ltc1660_id);232 233static struct spi_driver ltc1660_driver = {234	.driver = {235		.name = "ltc1660",236		.of_match_table = ltc1660_dt_ids,237		.pm = pm_sleep_ptr(&ltc1660_pm_ops),238	},239	.probe	= ltc1660_probe,240	.remove = ltc1660_remove,241	.id_table = ltc1660_id,242};243module_spi_driver(ltc1660_driver);244 245MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");246MODULE_DESCRIPTION("Linear Technology LTC1660/LTC1665 DAC");247MODULE_LICENSE("GPL v2");248