brintos

brintos / linux-shallow public Read only

0
0
Text · 14.5 KiB · f28880e Raw
400 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Industrial I/O driver for Microchip digital potentiometers4 * Copyright (c) 2015  Axentia Technologies AB5 * Author: Peter Rosin <peda@axentia.se>6 *7 * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf8 *9 * DEVID	#Wipers	#Positions	Resistor Opts (kOhm)	i2c address10 * mcp4531	1	129		5, 10, 50, 100          010111x11 * mcp4532	1	129		5, 10, 50, 100          01011xx12 * mcp4541	1	129		5, 10, 50, 100          010111x13 * mcp4542	1	129		5, 10, 50, 100          01011xx14 * mcp4551	1	257		5, 10, 50, 100          010111x15 * mcp4552	1	257		5, 10, 50, 100          01011xx16 * mcp4561	1	257		5, 10, 50, 100          010111x17 * mcp4562	1	257		5, 10, 50, 100          01011xx18 * mcp4631	2	129		5, 10, 50, 100          0101xxx19 * mcp4632	2	129		5, 10, 50, 100          01011xx20 * mcp4641	2	129		5, 10, 50, 100          0101xxx21 * mcp4642	2	129		5, 10, 50, 100          01011xx22 * mcp4651	2	257		5, 10, 50, 100          0101xxx23 * mcp4652	2	257		5, 10, 50, 100          01011xx24 * mcp4661	2	257		5, 10, 50, 100          0101xxx25 * mcp4662	2	257		5, 10, 50, 100          01011xx26 */27 28#include <linux/module.h>29#include <linux/i2c.h>30#include <linux/err.h>31#include <linux/mod_devicetable.h>32#include <linux/property.h>33 34#include <linux/iio/iio.h>35 36struct mcp4531_cfg {37	int wipers;38	int avail[3];39	int kohms;40};41 42enum mcp4531_type {43	MCP453x_502,44	MCP453x_103,45	MCP453x_503,46	MCP453x_104,47	MCP454x_502,48	MCP454x_103,49	MCP454x_503,50	MCP454x_104,51	MCP455x_502,52	MCP455x_103,53	MCP455x_503,54	MCP455x_104,55	MCP456x_502,56	MCP456x_103,57	MCP456x_503,58	MCP456x_104,59	MCP463x_502,60	MCP463x_103,61	MCP463x_503,62	MCP463x_104,63	MCP464x_502,64	MCP464x_103,65	MCP464x_503,66	MCP464x_104,67	MCP465x_502,68	MCP465x_103,69	MCP465x_503,70	MCP465x_104,71	MCP466x_502,72	MCP466x_103,73	MCP466x_503,74	MCP466x_104,75};76 77static const struct mcp4531_cfg mcp4531_cfg[] = {78	[MCP453x_502] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms =   5, },79	[MCP453x_103] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms =  10, },80	[MCP453x_503] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms =  50, },81	[MCP453x_104] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 100, },82	[MCP454x_502] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms =   5, },83	[MCP454x_103] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms =  10, },84	[MCP454x_503] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms =  50, },85	[MCP454x_104] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 100, },86	[MCP455x_502] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms =   5, },87	[MCP455x_103] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms =  10, },88	[MCP455x_503] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms =  50, },89	[MCP455x_104] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 100, },90	[MCP456x_502] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms =   5, },91	[MCP456x_103] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms =  10, },92	[MCP456x_503] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms =  50, },93	[MCP456x_104] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 100, },94	[MCP463x_502] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms =   5, },95	[MCP463x_103] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms =  10, },96	[MCP463x_503] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms =  50, },97	[MCP463x_104] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 100, },98	[MCP464x_502] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms =   5, },99	[MCP464x_103] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms =  10, },100	[MCP464x_503] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms =  50, },101	[MCP464x_104] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 100, },102	[MCP465x_502] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms =   5, },103	[MCP465x_103] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms =  10, },104	[MCP465x_503] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms =  50, },105	[MCP465x_104] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 100, },106	[MCP466x_502] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms =   5, },107	[MCP466x_103] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms =  10, },108	[MCP466x_503] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms =  50, },109	[MCP466x_104] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 100, },110};111 112#define MCP4531_WRITE (0 << 2)113#define MCP4531_INCR  (1 << 2)114#define MCP4531_DECR  (2 << 2)115#define MCP4531_READ  (3 << 2)116 117#define MCP4531_WIPER_SHIFT (4)118 119struct mcp4531_data {120	struct i2c_client *client;121	const struct mcp4531_cfg *cfg;122};123 124#define MCP4531_CHANNEL(ch) {						\125	.type = IIO_RESISTANCE,						\126	.indexed = 1,							\127	.output = 1,							\128	.channel = (ch),						\129	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\130	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\131	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW),	\132}133 134static const struct iio_chan_spec mcp4531_channels[] = {135	MCP4531_CHANNEL(0),136	MCP4531_CHANNEL(1),137};138 139static int mcp4531_read_raw(struct iio_dev *indio_dev,140			    struct iio_chan_spec const *chan,141			    int *val, int *val2, long mask)142{143	struct mcp4531_data *data = iio_priv(indio_dev);144	int address = chan->channel << MCP4531_WIPER_SHIFT;145	s32 ret;146 147	switch (mask) {148	case IIO_CHAN_INFO_RAW:149		ret = i2c_smbus_read_word_swapped(data->client,150						  MCP4531_READ | address);151		if (ret < 0)152			return ret;153		*val = ret;154		return IIO_VAL_INT;155	case IIO_CHAN_INFO_SCALE:156		*val = 1000 * data->cfg->kohms;157		*val2 = data->cfg->avail[2];158		return IIO_VAL_FRACTIONAL;159	}160 161	return -EINVAL;162}163 164static int mcp4531_read_avail(struct iio_dev *indio_dev,165			      struct iio_chan_spec const *chan,166			      const int **vals, int *type, int *length,167			      long mask)168{169	struct mcp4531_data *data = iio_priv(indio_dev);170 171	switch (mask) {172	case IIO_CHAN_INFO_RAW:173		*length = ARRAY_SIZE(data->cfg->avail);174		*vals = data->cfg->avail;175		*type = IIO_VAL_INT;176		return IIO_AVAIL_RANGE;177	}178 179	return -EINVAL;180}181 182static int mcp4531_write_raw(struct iio_dev *indio_dev,183			     struct iio_chan_spec const *chan,184			     int val, int val2, long mask)185{186	struct mcp4531_data *data = iio_priv(indio_dev);187	int address = chan->channel << MCP4531_WIPER_SHIFT;188 189	switch (mask) {190	case IIO_CHAN_INFO_RAW:191		if (val > data->cfg->avail[2] || val < 0)192			return -EINVAL;193		break;194	default:195		return -EINVAL;196	}197 198	return i2c_smbus_write_byte_data(data->client,199					 MCP4531_WRITE | address | (val >> 8),200					 val & 0xff);201}202 203static const struct iio_info mcp4531_info = {204	.read_raw = mcp4531_read_raw,205	.read_avail = mcp4531_read_avail,206	.write_raw = mcp4531_write_raw,207};208 209#define MCP4531_ID_TABLE(_name, cfg) {				\210	.name = _name,						\211	.driver_data = (kernel_ulong_t)&mcp4531_cfg[cfg],	\212}213 214static const struct i2c_device_id mcp4531_id[] = {215	MCP4531_ID_TABLE("mcp4531-502", MCP453x_502),216	MCP4531_ID_TABLE("mcp4531-103", MCP453x_103),217	MCP4531_ID_TABLE("mcp4531-503", MCP453x_503),218	MCP4531_ID_TABLE("mcp4531-104", MCP453x_104),219	MCP4531_ID_TABLE("mcp4532-502", MCP453x_502),220	MCP4531_ID_TABLE("mcp4532-103", MCP453x_103),221	MCP4531_ID_TABLE("mcp4532-503", MCP453x_503),222	MCP4531_ID_TABLE("mcp4532-104", MCP453x_104),223	MCP4531_ID_TABLE("mcp4541-502", MCP454x_502),224	MCP4531_ID_TABLE("mcp4541-103", MCP454x_103),225	MCP4531_ID_TABLE("mcp4541-503", MCP454x_503),226	MCP4531_ID_TABLE("mcp4541-104", MCP454x_104),227	MCP4531_ID_TABLE("mcp4542-502", MCP454x_502),228	MCP4531_ID_TABLE("mcp4542-103", MCP454x_103),229	MCP4531_ID_TABLE("mcp4542-503", MCP454x_503),230	MCP4531_ID_TABLE("mcp4542-104", MCP454x_104),231	MCP4531_ID_TABLE("mcp4551-502", MCP455x_502),232	MCP4531_ID_TABLE("mcp4551-103", MCP455x_103),233	MCP4531_ID_TABLE("mcp4551-503", MCP455x_503),234	MCP4531_ID_TABLE("mcp4551-104", MCP455x_104),235	MCP4531_ID_TABLE("mcp4552-502", MCP455x_502),236	MCP4531_ID_TABLE("mcp4552-103", MCP455x_103),237	MCP4531_ID_TABLE("mcp4552-503", MCP455x_503),238	MCP4531_ID_TABLE("mcp4552-104", MCP455x_104),239	MCP4531_ID_TABLE("mcp4561-502", MCP456x_502),240	MCP4531_ID_TABLE("mcp4561-103", MCP456x_103),241	MCP4531_ID_TABLE("mcp4561-503", MCP456x_503),242	MCP4531_ID_TABLE("mcp4561-104", MCP456x_104),243	MCP4531_ID_TABLE("mcp4562-502", MCP456x_502),244	MCP4531_ID_TABLE("mcp4562-103", MCP456x_103),245	MCP4531_ID_TABLE("mcp4562-503", MCP456x_503),246	MCP4531_ID_TABLE("mcp4562-104", MCP456x_104),247	MCP4531_ID_TABLE("mcp4631-502", MCP463x_502),248	MCP4531_ID_TABLE("mcp4631-103", MCP463x_103),249	MCP4531_ID_TABLE("mcp4631-503", MCP463x_503),250	MCP4531_ID_TABLE("mcp4631-104", MCP463x_104),251	MCP4531_ID_TABLE("mcp4632-502", MCP463x_502),252	MCP4531_ID_TABLE("mcp4632-103", MCP463x_103),253	MCP4531_ID_TABLE("mcp4632-503", MCP463x_503),254	MCP4531_ID_TABLE("mcp4632-104", MCP463x_104),255	MCP4531_ID_TABLE("mcp4641-502", MCP464x_502),256	MCP4531_ID_TABLE("mcp4641-103", MCP464x_103),257	MCP4531_ID_TABLE("mcp4641-503", MCP464x_503),258	MCP4531_ID_TABLE("mcp4641-104", MCP464x_104),259	MCP4531_ID_TABLE("mcp4642-502", MCP464x_502),260	MCP4531_ID_TABLE("mcp4642-103", MCP464x_103),261	MCP4531_ID_TABLE("mcp4642-503", MCP464x_503),262	MCP4531_ID_TABLE("mcp4642-104", MCP464x_104),263	MCP4531_ID_TABLE("mcp4651-502", MCP465x_502),264	MCP4531_ID_TABLE("mcp4651-103", MCP465x_103),265	MCP4531_ID_TABLE("mcp4651-503", MCP465x_503),266	MCP4531_ID_TABLE("mcp4651-104", MCP465x_104),267	MCP4531_ID_TABLE("mcp4652-502", MCP465x_502),268	MCP4531_ID_TABLE("mcp4652-103", MCP465x_103),269	MCP4531_ID_TABLE("mcp4652-503", MCP465x_503),270	MCP4531_ID_TABLE("mcp4652-104", MCP465x_104),271	MCP4531_ID_TABLE("mcp4661-502", MCP466x_502),272	MCP4531_ID_TABLE("mcp4661-103", MCP466x_103),273	MCP4531_ID_TABLE("mcp4661-503", MCP466x_503),274	MCP4531_ID_TABLE("mcp4661-104", MCP466x_104),275	MCP4531_ID_TABLE("mcp4662-502", MCP466x_502),276	MCP4531_ID_TABLE("mcp4662-103", MCP466x_103),277	MCP4531_ID_TABLE("mcp4662-503", MCP466x_503),278	MCP4531_ID_TABLE("mcp4662-104", MCP466x_104),279	{ /* sentinel */ }280};281MODULE_DEVICE_TABLE(i2c, mcp4531_id);282 283#define MCP4531_COMPATIBLE(of_compatible, cfg) {	\284			.compatible = of_compatible,	\285			.data = &mcp4531_cfg[cfg],	\286}287 288static const struct of_device_id mcp4531_of_match[] = {289	MCP4531_COMPATIBLE("microchip,mcp4531-502", MCP453x_502),290	MCP4531_COMPATIBLE("microchip,mcp4531-103", MCP453x_103),291	MCP4531_COMPATIBLE("microchip,mcp4531-503", MCP453x_503),292	MCP4531_COMPATIBLE("microchip,mcp4531-104", MCP453x_104),293	MCP4531_COMPATIBLE("microchip,mcp4532-502", MCP453x_502),294	MCP4531_COMPATIBLE("microchip,mcp4532-103", MCP453x_103),295	MCP4531_COMPATIBLE("microchip,mcp4532-503", MCP453x_503),296	MCP4531_COMPATIBLE("microchip,mcp4532-104", MCP453x_104),297	MCP4531_COMPATIBLE("microchip,mcp4541-502", MCP454x_502),298	MCP4531_COMPATIBLE("microchip,mcp4541-103", MCP454x_103),299	MCP4531_COMPATIBLE("microchip,mcp4541-503", MCP454x_503),300	MCP4531_COMPATIBLE("microchip,mcp4541-104", MCP454x_104),301	MCP4531_COMPATIBLE("microchip,mcp4542-502", MCP454x_502),302	MCP4531_COMPATIBLE("microchip,mcp4542-103", MCP454x_103),303	MCP4531_COMPATIBLE("microchip,mcp4542-503", MCP454x_503),304	MCP4531_COMPATIBLE("microchip,mcp4542-104", MCP454x_104),305	MCP4531_COMPATIBLE("microchip,mcp4551-502", MCP455x_502),306	MCP4531_COMPATIBLE("microchip,mcp4551-103", MCP455x_103),307	MCP4531_COMPATIBLE("microchip,mcp4551-503", MCP455x_503),308	MCP4531_COMPATIBLE("microchip,mcp4551-104", MCP455x_104),309	MCP4531_COMPATIBLE("microchip,mcp4552-502", MCP455x_502),310	MCP4531_COMPATIBLE("microchip,mcp4552-103", MCP455x_103),311	MCP4531_COMPATIBLE("microchip,mcp4552-503", MCP455x_503),312	MCP4531_COMPATIBLE("microchip,mcp4552-104", MCP455x_104),313	MCP4531_COMPATIBLE("microchip,mcp4561-502", MCP456x_502),314	MCP4531_COMPATIBLE("microchip,mcp4561-103", MCP456x_103),315	MCP4531_COMPATIBLE("microchip,mcp4561-503", MCP456x_503),316	MCP4531_COMPATIBLE("microchip,mcp4561-104", MCP456x_104),317	MCP4531_COMPATIBLE("microchip,mcp4562-502", MCP456x_502),318	MCP4531_COMPATIBLE("microchip,mcp4562-103", MCP456x_103),319	MCP4531_COMPATIBLE("microchip,mcp4562-503", MCP456x_503),320	MCP4531_COMPATIBLE("microchip,mcp4562-104", MCP456x_104),321	MCP4531_COMPATIBLE("microchip,mcp4631-502", MCP463x_502),322	MCP4531_COMPATIBLE("microchip,mcp4631-103", MCP463x_103),323	MCP4531_COMPATIBLE("microchip,mcp4631-503", MCP463x_503),324	MCP4531_COMPATIBLE("microchip,mcp4631-104", MCP463x_104),325	MCP4531_COMPATIBLE("microchip,mcp4632-502", MCP463x_502),326	MCP4531_COMPATIBLE("microchip,mcp4632-103", MCP463x_103),327	MCP4531_COMPATIBLE("microchip,mcp4632-503", MCP463x_503),328	MCP4531_COMPATIBLE("microchip,mcp4632-104", MCP463x_104),329	MCP4531_COMPATIBLE("microchip,mcp4641-502", MCP464x_502),330	MCP4531_COMPATIBLE("microchip,mcp4641-103", MCP464x_103),331	MCP4531_COMPATIBLE("microchip,mcp4641-503", MCP464x_503),332	MCP4531_COMPATIBLE("microchip,mcp4641-104", MCP464x_104),333	MCP4531_COMPATIBLE("microchip,mcp4642-502", MCP464x_502),334	MCP4531_COMPATIBLE("microchip,mcp4642-103", MCP464x_103),335	MCP4531_COMPATIBLE("microchip,mcp4642-503", MCP464x_503),336	MCP4531_COMPATIBLE("microchip,mcp4642-104", MCP464x_104),337	MCP4531_COMPATIBLE("microchip,mcp4651-502", MCP465x_502),338	MCP4531_COMPATIBLE("microchip,mcp4651-103", MCP465x_103),339	MCP4531_COMPATIBLE("microchip,mcp4651-503", MCP465x_503),340	MCP4531_COMPATIBLE("microchip,mcp4651-104", MCP465x_104),341	MCP4531_COMPATIBLE("microchip,mcp4652-502", MCP465x_502),342	MCP4531_COMPATIBLE("microchip,mcp4652-103", MCP465x_103),343	MCP4531_COMPATIBLE("microchip,mcp4652-503", MCP465x_503),344	MCP4531_COMPATIBLE("microchip,mcp4652-104", MCP465x_104),345	MCP4531_COMPATIBLE("microchip,mcp4661-502", MCP466x_502),346	MCP4531_COMPATIBLE("microchip,mcp4661-103", MCP466x_103),347	MCP4531_COMPATIBLE("microchip,mcp4661-503", MCP466x_503),348	MCP4531_COMPATIBLE("microchip,mcp4661-104", MCP466x_104),349	MCP4531_COMPATIBLE("microchip,mcp4662-502", MCP466x_502),350	MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103),351	MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503),352	MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104),353	{ /* sentinel */ }354};355MODULE_DEVICE_TABLE(of, mcp4531_of_match);356 357static int mcp4531_probe(struct i2c_client *client)358{359	struct device *dev = &client->dev;360	struct mcp4531_data *data;361	struct iio_dev *indio_dev;362 363	if (!i2c_check_functionality(client->adapter,364				     I2C_FUNC_SMBUS_WORD_DATA)) {365		dev_err(dev, "SMBUS Word Data not supported\n");366		return -EOPNOTSUPP;367	}368 369	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));370	if (!indio_dev)371		return -ENOMEM;372	data = iio_priv(indio_dev);373	i2c_set_clientdata(client, indio_dev);374	data->client = client;375 376	data->cfg = i2c_get_match_data(client);377 378	indio_dev->info = &mcp4531_info;379	indio_dev->channels = mcp4531_channels;380	indio_dev->num_channels = data->cfg->wipers;381	indio_dev->name = client->name;382 383	return devm_iio_device_register(dev, indio_dev);384}385 386static struct i2c_driver mcp4531_driver = {387	.driver = {388		.name	= "mcp4531",389		.of_match_table = mcp4531_of_match,390	},391	.probe		= mcp4531_probe,392	.id_table	= mcp4531_id,393};394 395module_i2c_driver(mcp4531_driver);396 397MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");398MODULE_DESCRIPTION("MCP4531 digital potentiometer");399MODULE_LICENSE("GPL v2");400