brintos

brintos / linux-shallow public Read only

0
0
Text · 14.8 KiB · 7890c09 Raw
493 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Industrial I/O driver for Microchip digital potentiometers4 *5 * Copyright (c) 2016 Slawomir Stepien6 * Based on: Peter Rosin's code from mcp4531.c7 *8 * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf9 *10 * DEVID	#Wipers	#Positions	Resistor Opts (kOhm)11 * mcp4131	1	129		5, 10, 50, 10012 * mcp4132	1	129		5, 10, 50, 10013 * mcp4141	1	129		5, 10, 50, 10014 * mcp4142	1	129		5, 10, 50, 10015 * mcp4151	1	257		5, 10, 50, 10016 * mcp4152	1	257		5, 10, 50, 10017 * mcp4161	1	257		5, 10, 50, 10018 * mcp4162	1	257		5, 10, 50, 10019 * mcp4231	2	129		5, 10, 50, 10020 * mcp4232	2	129		5, 10, 50, 10021 * mcp4241	2	129		5, 10, 50, 10022 * mcp4242	2	129		5, 10, 50, 10023 * mcp4251	2	257		5, 10, 50, 10024 * mcp4252	2	257		5, 10, 50, 10025 * mcp4261	2	257		5, 10, 50, 10026 * mcp4262	2	257		5, 10, 50, 10027 */28 29/*30 * TODO:31 * 1. Write wiper setting to EEPROM for EEPROM capable models.32 */33 34#include <linux/cache.h>35#include <linux/err.h>36#include <linux/export.h>37#include <linux/iio/iio.h>38#include <linux/iio/types.h>39#include <linux/module.h>40#include <linux/mod_devicetable.h>41#include <linux/mutex.h>42#include <linux/property.h>43#include <linux/spi/spi.h>44 45#define MCP4131_WRITE		(0x00 << 2)46#define MCP4131_READ		(0x03 << 2)47 48#define MCP4131_WIPER_SHIFT	449#define MCP4131_CMDERR(r)	((r[0]) & 0x02)50#define MCP4131_RAW(r)		((r[0]) == 0xff ? 0x100 : (r[1]))51 52struct mcp4131_cfg {53	int wipers;54	int max_pos;55	int kohms;56};57 58enum mcp4131_type {59	MCP413x_502 = 0,60	MCP413x_103,61	MCP413x_503,62	MCP413x_104,63	MCP414x_502,64	MCP414x_103,65	MCP414x_503,66	MCP414x_104,67	MCP415x_502,68	MCP415x_103,69	MCP415x_503,70	MCP415x_104,71	MCP416x_502,72	MCP416x_103,73	MCP416x_503,74	MCP416x_104,75	MCP423x_502,76	MCP423x_103,77	MCP423x_503,78	MCP423x_104,79	MCP424x_502,80	MCP424x_103,81	MCP424x_503,82	MCP424x_104,83	MCP425x_502,84	MCP425x_103,85	MCP425x_503,86	MCP425x_104,87	MCP426x_502,88	MCP426x_103,89	MCP426x_503,90	MCP426x_104,91};92 93static const struct mcp4131_cfg mcp4131_cfg[] = {94	[MCP413x_502] = { .wipers = 1, .max_pos = 128, .kohms =   5, },95	[MCP413x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },96	[MCP413x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },97	[MCP413x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },98	[MCP414x_502] = { .wipers = 1, .max_pos = 128, .kohms =   5, },99	[MCP414x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },100	[MCP414x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },101	[MCP414x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },102	[MCP415x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },103	[MCP415x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },104	[MCP415x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },105	[MCP415x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },106	[MCP416x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },107	[MCP416x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },108	[MCP416x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },109	[MCP416x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },110	[MCP423x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },111	[MCP423x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },112	[MCP423x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },113	[MCP423x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },114	[MCP424x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },115	[MCP424x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },116	[MCP424x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },117	[MCP424x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },118	[MCP425x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },119	[MCP425x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },120	[MCP425x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },121	[MCP425x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },122	[MCP426x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },123	[MCP426x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },124	[MCP426x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },125	[MCP426x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },126};127 128struct mcp4131_data {129	struct spi_device *spi;130	const struct mcp4131_cfg *cfg;131	struct mutex lock;132	u8 buf[2] __aligned(IIO_DMA_MINALIGN);133};134 135#define MCP4131_CHANNEL(ch) {					\136	.type = IIO_RESISTANCE,					\137	.indexed = 1,						\138	.output = 1,						\139	.channel = (ch),					\140	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\141	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\142}143 144static const struct iio_chan_spec mcp4131_channels[] = {145	MCP4131_CHANNEL(0),146	MCP4131_CHANNEL(1),147};148 149static int mcp4131_read(struct spi_device *spi, void *buf, size_t len)150{151	struct spi_transfer t = {152		.tx_buf = buf, /* We need to send addr, cmd and 12 bits */153		.rx_buf	= buf,154		.len = len,155	};156	struct spi_message m;157 158	spi_message_init(&m);159	spi_message_add_tail(&t, &m);160 161	return spi_sync(spi, &m);162}163 164static int mcp4131_read_raw(struct iio_dev *indio_dev,165			    struct iio_chan_spec const *chan,166			    int *val, int *val2, long mask)167{168	int err;169	struct mcp4131_data *data = iio_priv(indio_dev);170	int address = chan->channel;171 172	switch (mask) {173	case IIO_CHAN_INFO_RAW:174		mutex_lock(&data->lock);175 176		data->buf[0] = (address << MCP4131_WIPER_SHIFT) | MCP4131_READ;177		data->buf[1] = 0;178 179		err = mcp4131_read(data->spi, data->buf, 2);180		if (err) {181			mutex_unlock(&data->lock);182			return err;183		}184 185		/* Error, bad address/command combination */186		if (!MCP4131_CMDERR(data->buf)) {187			mutex_unlock(&data->lock);188			return -EIO;189		}190 191		*val = MCP4131_RAW(data->buf);192		mutex_unlock(&data->lock);193 194		return IIO_VAL_INT;195 196	case IIO_CHAN_INFO_SCALE:197		*val = 1000 * data->cfg->kohms;198		*val2 = data->cfg->max_pos;199		return IIO_VAL_FRACTIONAL;200	}201 202	return -EINVAL;203}204 205static int mcp4131_write_raw(struct iio_dev *indio_dev,206			     struct iio_chan_spec const *chan,207			     int val, int val2, long mask)208{209	int err;210	struct mcp4131_data *data = iio_priv(indio_dev);211	int address = chan->channel << MCP4131_WIPER_SHIFT;212 213	switch (mask) {214	case IIO_CHAN_INFO_RAW:215		if (val > data->cfg->max_pos || val < 0)216			return -EINVAL;217		break;218 219	default:220		return -EINVAL;221	}222 223	mutex_lock(&data->lock);224 225	data->buf[0] = address << MCP4131_WIPER_SHIFT;226	data->buf[0] |= MCP4131_WRITE | (val >> 8);227	data->buf[1] = val & 0xFF; /* 8 bits here */228 229	err = spi_write(data->spi, data->buf, 2);230	mutex_unlock(&data->lock);231 232	return err;233}234 235static const struct iio_info mcp4131_info = {236	.read_raw = mcp4131_read_raw,237	.write_raw = mcp4131_write_raw,238};239 240static int mcp4131_probe(struct spi_device *spi)241{242	int err;243	struct device *dev = &spi->dev;244	unsigned long devid;245	struct mcp4131_data *data;246	struct iio_dev *indio_dev;247 248	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));249	if (!indio_dev)250		return -ENOMEM;251 252	data = iio_priv(indio_dev);253	spi_set_drvdata(spi, indio_dev);254	data->spi = spi;255	data->cfg = device_get_match_data(&spi->dev);256	if (!data->cfg) {257		devid = spi_get_device_id(spi)->driver_data;258		data->cfg = &mcp4131_cfg[devid];259	}260 261	mutex_init(&data->lock);262 263	indio_dev->info = &mcp4131_info;264	indio_dev->channels = mcp4131_channels;265	indio_dev->num_channels = data->cfg->wipers;266	indio_dev->name = spi_get_device_id(spi)->name;267 268	err = devm_iio_device_register(dev, indio_dev);269	if (err) {270		dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);271		return err;272	}273 274	return 0;275}276 277static const struct of_device_id mcp4131_dt_ids[] = {278	{ .compatible = "microchip,mcp4131-502",279		.data = &mcp4131_cfg[MCP413x_502] },280	{ .compatible = "microchip,mcp4131-103",281		.data = &mcp4131_cfg[MCP413x_103] },282	{ .compatible = "microchip,mcp4131-503",283		.data = &mcp4131_cfg[MCP413x_503] },284	{ .compatible = "microchip,mcp4131-104",285		.data = &mcp4131_cfg[MCP413x_104] },286	{ .compatible = "microchip,mcp4132-502",287		.data = &mcp4131_cfg[MCP413x_502] },288	{ .compatible = "microchip,mcp4132-103",289		.data = &mcp4131_cfg[MCP413x_103] },290	{ .compatible = "microchip,mcp4132-503",291		.data = &mcp4131_cfg[MCP413x_503] },292	{ .compatible = "microchip,mcp4132-104",293		.data = &mcp4131_cfg[MCP413x_104] },294	{ .compatible = "microchip,mcp4141-502",295		.data = &mcp4131_cfg[MCP414x_502] },296	{ .compatible = "microchip,mcp4141-103",297		.data = &mcp4131_cfg[MCP414x_103] },298	{ .compatible = "microchip,mcp4141-503",299		.data = &mcp4131_cfg[MCP414x_503] },300	{ .compatible = "microchip,mcp4141-104",301		.data = &mcp4131_cfg[MCP414x_104] },302	{ .compatible = "microchip,mcp4142-502",303		.data = &mcp4131_cfg[MCP414x_502] },304	{ .compatible = "microchip,mcp4142-103",305		.data = &mcp4131_cfg[MCP414x_103] },306	{ .compatible = "microchip,mcp4142-503",307		.data = &mcp4131_cfg[MCP414x_503] },308	{ .compatible = "microchip,mcp4142-104",309		.data = &mcp4131_cfg[MCP414x_104] },310	{ .compatible = "microchip,mcp4151-502",311		.data = &mcp4131_cfg[MCP415x_502] },312	{ .compatible = "microchip,mcp4151-103",313		.data = &mcp4131_cfg[MCP415x_103] },314	{ .compatible = "microchip,mcp4151-503",315		.data = &mcp4131_cfg[MCP415x_503] },316	{ .compatible = "microchip,mcp4151-104",317		.data = &mcp4131_cfg[MCP415x_104] },318	{ .compatible = "microchip,mcp4152-502",319		.data = &mcp4131_cfg[MCP415x_502] },320	{ .compatible = "microchip,mcp4152-103",321		.data = &mcp4131_cfg[MCP415x_103] },322	{ .compatible = "microchip,mcp4152-503",323		.data = &mcp4131_cfg[MCP415x_503] },324	{ .compatible = "microchip,mcp4152-104",325		.data = &mcp4131_cfg[MCP415x_104] },326	{ .compatible = "microchip,mcp4161-502",327		.data = &mcp4131_cfg[MCP416x_502] },328	{ .compatible = "microchip,mcp4161-103",329		.data = &mcp4131_cfg[MCP416x_103] },330	{ .compatible = "microchip,mcp4161-503",331		.data = &mcp4131_cfg[MCP416x_503] },332	{ .compatible = "microchip,mcp4161-104",333		.data = &mcp4131_cfg[MCP416x_104] },334	{ .compatible = "microchip,mcp4162-502",335		.data = &mcp4131_cfg[MCP416x_502] },336	{ .compatible = "microchip,mcp4162-103",337		.data = &mcp4131_cfg[MCP416x_103] },338	{ .compatible = "microchip,mcp4162-503",339		.data = &mcp4131_cfg[MCP416x_503] },340	{ .compatible = "microchip,mcp4162-104",341		.data = &mcp4131_cfg[MCP416x_104] },342	{ .compatible = "microchip,mcp4231-502",343		.data = &mcp4131_cfg[MCP423x_502] },344	{ .compatible = "microchip,mcp4231-103",345		.data = &mcp4131_cfg[MCP423x_103] },346	{ .compatible = "microchip,mcp4231-503",347		.data = &mcp4131_cfg[MCP423x_503] },348	{ .compatible = "microchip,mcp4231-104",349		.data = &mcp4131_cfg[MCP423x_104] },350	{ .compatible = "microchip,mcp4232-502",351		.data = &mcp4131_cfg[MCP423x_502] },352	{ .compatible = "microchip,mcp4232-103",353		.data = &mcp4131_cfg[MCP423x_103] },354	{ .compatible = "microchip,mcp4232-503",355		.data = &mcp4131_cfg[MCP423x_503] },356	{ .compatible = "microchip,mcp4232-104",357		.data = &mcp4131_cfg[MCP423x_104] },358	{ .compatible = "microchip,mcp4241-502",359		.data = &mcp4131_cfg[MCP424x_502] },360	{ .compatible = "microchip,mcp4241-103",361		.data = &mcp4131_cfg[MCP424x_103] },362	{ .compatible = "microchip,mcp4241-503",363		.data = &mcp4131_cfg[MCP424x_503] },364	{ .compatible = "microchip,mcp4241-104",365		.data = &mcp4131_cfg[MCP424x_104] },366	{ .compatible = "microchip,mcp4242-502",367		.data = &mcp4131_cfg[MCP424x_502] },368	{ .compatible = "microchip,mcp4242-103",369		.data = &mcp4131_cfg[MCP424x_103] },370	{ .compatible = "microchip,mcp4242-503",371		.data = &mcp4131_cfg[MCP424x_503] },372	{ .compatible = "microchip,mcp4242-104",373		.data = &mcp4131_cfg[MCP424x_104] },374	{ .compatible = "microchip,mcp4251-502",375		.data = &mcp4131_cfg[MCP425x_502] },376	{ .compatible = "microchip,mcp4251-103",377		.data = &mcp4131_cfg[MCP425x_103] },378	{ .compatible = "microchip,mcp4251-503",379		.data = &mcp4131_cfg[MCP425x_503] },380	{ .compatible = "microchip,mcp4251-104",381		.data = &mcp4131_cfg[MCP425x_104] },382	{ .compatible = "microchip,mcp4252-502",383		.data = &mcp4131_cfg[MCP425x_502] },384	{ .compatible = "microchip,mcp4252-103",385		.data = &mcp4131_cfg[MCP425x_103] },386	{ .compatible = "microchip,mcp4252-503",387		.data = &mcp4131_cfg[MCP425x_503] },388	{ .compatible = "microchip,mcp4252-104",389		.data = &mcp4131_cfg[MCP425x_104] },390	{ .compatible = "microchip,mcp4261-502",391		.data = &mcp4131_cfg[MCP426x_502] },392	{ .compatible = "microchip,mcp4261-103",393		.data = &mcp4131_cfg[MCP426x_103] },394	{ .compatible = "microchip,mcp4261-503",395		.data = &mcp4131_cfg[MCP426x_503] },396	{ .compatible = "microchip,mcp4261-104",397		.data = &mcp4131_cfg[MCP426x_104] },398	{ .compatible = "microchip,mcp4262-502",399		.data = &mcp4131_cfg[MCP426x_502] },400	{ .compatible = "microchip,mcp4262-103",401		.data = &mcp4131_cfg[MCP426x_103] },402	{ .compatible = "microchip,mcp4262-503",403		.data = &mcp4131_cfg[MCP426x_503] },404	{ .compatible = "microchip,mcp4262-104",405		.data = &mcp4131_cfg[MCP426x_104] },406	{}407};408MODULE_DEVICE_TABLE(of, mcp4131_dt_ids);409 410static const struct spi_device_id mcp4131_id[] = {411	{ "mcp4131-502", MCP413x_502 },412	{ "mcp4131-103", MCP413x_103 },413	{ "mcp4131-503", MCP413x_503 },414	{ "mcp4131-104", MCP413x_104 },415	{ "mcp4132-502", MCP413x_502 },416	{ "mcp4132-103", MCP413x_103 },417	{ "mcp4132-503", MCP413x_503 },418	{ "mcp4132-104", MCP413x_104 },419	{ "mcp4141-502", MCP414x_502 },420	{ "mcp4141-103", MCP414x_103 },421	{ "mcp4141-503", MCP414x_503 },422	{ "mcp4141-104", MCP414x_104 },423	{ "mcp4142-502", MCP414x_502 },424	{ "mcp4142-103", MCP414x_103 },425	{ "mcp4142-503", MCP414x_503 },426	{ "mcp4142-104", MCP414x_104 },427	{ "mcp4151-502", MCP415x_502 },428	{ "mcp4151-103", MCP415x_103 },429	{ "mcp4151-503", MCP415x_503 },430	{ "mcp4151-104", MCP415x_104 },431	{ "mcp4152-502", MCP415x_502 },432	{ "mcp4152-103", MCP415x_103 },433	{ "mcp4152-503", MCP415x_503 },434	{ "mcp4152-104", MCP415x_104 },435	{ "mcp4161-502", MCP416x_502 },436	{ "mcp4161-103", MCP416x_103 },437	{ "mcp4161-503", MCP416x_503 },438	{ "mcp4161-104", MCP416x_104 },439	{ "mcp4162-502", MCP416x_502 },440	{ "mcp4162-103", MCP416x_103 },441	{ "mcp4162-503", MCP416x_503 },442	{ "mcp4162-104", MCP416x_104 },443	{ "mcp4231-502", MCP423x_502 },444	{ "mcp4231-103", MCP423x_103 },445	{ "mcp4231-503", MCP423x_503 },446	{ "mcp4231-104", MCP423x_104 },447	{ "mcp4232-502", MCP423x_502 },448	{ "mcp4232-103", MCP423x_103 },449	{ "mcp4232-503", MCP423x_503 },450	{ "mcp4232-104", MCP423x_104 },451	{ "mcp4241-502", MCP424x_502 },452	{ "mcp4241-103", MCP424x_103 },453	{ "mcp4241-503", MCP424x_503 },454	{ "mcp4241-104", MCP424x_104 },455	{ "mcp4242-502", MCP424x_502 },456	{ "mcp4242-103", MCP424x_103 },457	{ "mcp4242-503", MCP424x_503 },458	{ "mcp4242-104", MCP424x_104 },459	{ "mcp4251-502", MCP425x_502 },460	{ "mcp4251-103", MCP425x_103 },461	{ "mcp4251-503", MCP425x_503 },462	{ "mcp4251-104", MCP425x_104 },463	{ "mcp4252-502", MCP425x_502 },464	{ "mcp4252-103", MCP425x_103 },465	{ "mcp4252-503", MCP425x_503 },466	{ "mcp4252-104", MCP425x_104 },467	{ "mcp4261-502", MCP426x_502 },468	{ "mcp4261-103", MCP426x_103 },469	{ "mcp4261-503", MCP426x_503 },470	{ "mcp4261-104", MCP426x_104 },471	{ "mcp4262-502", MCP426x_502 },472	{ "mcp4262-103", MCP426x_103 },473	{ "mcp4262-503", MCP426x_503 },474	{ "mcp4262-104", MCP426x_104 },475	{}476};477MODULE_DEVICE_TABLE(spi, mcp4131_id);478 479static struct spi_driver mcp4131_driver = {480	.driver = {481		.name	= "mcp4131",482		.of_match_table = mcp4131_dt_ids,483	},484	.probe		= mcp4131_probe,485	.id_table	= mcp4131_id,486};487 488module_spi_driver(mcp4131_driver);489 490MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>");491MODULE_DESCRIPTION("MCP4131 digital potentiometer");492MODULE_LICENSE("GPL v2");493