1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Industrial I/O driver for Microchip digital potentiometers
4 *
5 * Copyright (c) 2016 Slawomir Stepien
6 * Based on: Peter Rosin's code from mcp4531.c
7 *
8 * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
9 *
10 * DEVID	#Wipers	#Positions	Resistor Opts (kOhm)
11 * mcp4131	1	129		5, 10, 50, 100
12 * mcp4132	1	129		5, 10, 50, 100
13 * mcp4141	1	129		5, 10, 50, 100
14 * mcp4142	1	129		5, 10, 50, 100
15 * mcp4151	1	257		5, 10, 50, 100
16 * mcp4152	1	257		5, 10, 50, 100
17 * mcp4161	1	257		5, 10, 50, 100
18 * mcp4162	1	257		5, 10, 50, 100
19 * mcp4231	2	129		5, 10, 50, 100
20 * mcp4232	2	129		5, 10, 50, 100
21 * mcp4241	2	129		5, 10, 50, 100
22 * mcp4242	2	129		5, 10, 50, 100
23 * mcp4251	2	257		5, 10, 50, 100
24 * mcp4252	2	257		5, 10, 50, 100
25 * mcp4261	2	257		5, 10, 50, 100
26 * mcp4262	2	257		5, 10, 50, 100
27 */
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	4
49#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] ____cacheline_aligned;
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