1238612Szeising// SPDX-License-Identifier: GPL-2.0 2158821Sjoel/* 3158821Sjoel * Industrial I/O driver for Microchip digital potentiometers 4158821Sjoel * Copyright (c) 2018 Axentia Technologies AB 5158821Sjoel * Author: Peter Rosin <peda@axentia.se> 6158821Sjoel * 7158821Sjoel * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22147a.pdf 8158821Sjoel * 9158821Sjoel * DEVID #Wipers #Positions Resistor Opts (kOhm) 10158821Sjoel * mcp4017 1 128 5, 10, 50, 100 11158821Sjoel * mcp4018 1 128 5, 10, 50, 100 12158821Sjoel * mcp4019 1 128 5, 10, 50, 100 13158821Sjoel */ 14158821Sjoel 15158821Sjoel#include <linux/err.h> 16158821Sjoel#include <linux/i2c.h> 17158821Sjoel#include <linux/iio/iio.h> 18158821Sjoel#include <linux/module.h> 19158821Sjoel#include <linux/mod_devicetable.h> 20158821Sjoel#include <linux/property.h> 21158821Sjoel 22158821Sjoel#define MCP4018_WIPER_MAX 127 23158821Sjoel 24158821Sjoelstruct mcp4018_cfg { 25158821Sjoel int kohms; 26158821Sjoel}; 27158821Sjoel 28158821Sjoelenum mcp4018_type { 29158821Sjoel MCP4018_502, 30158821Sjoel MCP4018_103, 31158821Sjoel MCP4018_503, 32158821Sjoel MCP4018_104, 33158821Sjoel}; 34158821Sjoel 35158821Sjoelstatic const struct mcp4018_cfg mcp4018_cfg[] = { 36158821Sjoel [MCP4018_502] = { .kohms = 5, }, 37158821Sjoel [MCP4018_103] = { .kohms = 10, }, 38158821Sjoel [MCP4018_503] = { .kohms = 50, }, 39158821Sjoel [MCP4018_104] = { .kohms = 100, }, 40158821Sjoel}; 41158821Sjoel 42158821Sjoelstruct mcp4018_data { 43158821Sjoel struct i2c_client *client; 44158821Sjoel const struct mcp4018_cfg *cfg; 45158821Sjoel}; 46158821Sjoel 47158821Sjoelstatic const struct iio_chan_spec mcp4018_channel = { 48158821Sjoel .type = IIO_RESISTANCE, 49158821Sjoel .indexed = 1, 50158821Sjoel .output = 1, 51158821Sjoel .channel = 0, 52158822Sjoel .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 53158821Sjoel .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 54158821Sjoel}; 55158821Sjoel 56158821Sjoelstatic int mcp4018_read_raw(struct iio_dev *indio_dev, 57162893Sru struct iio_chan_spec const *chan, 58158821Sjoel int *val, int *val2, long mask) 59158821Sjoel{ 60158821Sjoel struct mcp4018_data *data = iio_priv(indio_dev); 61162893Sru s32 ret; 62162893Sru 63162893Sru switch (mask) { 64158821Sjoel case IIO_CHAN_INFO_RAW: 65158821Sjoel ret = i2c_smbus_read_byte(data->client); 66158821Sjoel if (ret < 0) 67158821Sjoel return ret; 68158821Sjoel *val = ret; 69158821Sjoel return IIO_VAL_INT; 70158821Sjoel case IIO_CHAN_INFO_SCALE: 71162893Sru *val = 1000 * data->cfg->kohms; 72162893Sru *val2 = MCP4018_WIPER_MAX; 73158821Sjoel return IIO_VAL_FRACTIONAL; 74158821Sjoel } 75158821Sjoel 76158821Sjoel return -EINVAL; 77158821Sjoel} 78158821Sjoel 79158821Sjoelstatic int mcp4018_write_raw(struct iio_dev *indio_dev, 80158821Sjoel struct iio_chan_spec const *chan, 81158821Sjoel int val, int val2, long mask) 82158821Sjoel{ 83158821Sjoel struct mcp4018_data *data = iio_priv(indio_dev); 84158821Sjoel 85158821Sjoel switch (mask) { 86158821Sjoel case IIO_CHAN_INFO_RAW: 87158821Sjoel if (val > MCP4018_WIPER_MAX || val < 0) 88158821Sjoel return -EINVAL; 89158821Sjoel break; 90158821Sjoel default: 91158821Sjoel return -EINVAL; 92158821Sjoel } 93158821Sjoel 94158822Sjoel return i2c_smbus_write_byte(data->client, val); 95158821Sjoel} 96162893Sru 97158821Sjoelstatic const struct iio_info mcp4018_info = { 98158821Sjoel .read_raw = mcp4018_read_raw, 99158821Sjoel .write_raw = mcp4018_write_raw, 100158821Sjoel}; 101162893Sru 102158821Sjoel#define MCP4018_ID_TABLE(_name, cfg) { \ 103158821Sjoel .name = _name, \ 104158821Sjoel .driver_data = (kernel_ulong_t)&mcp4018_cfg[cfg], \ 105158821Sjoel} 106158821Sjoel 107158821Sjoelstatic const struct i2c_device_id mcp4018_id[] = { 108162893Sru MCP4018_ID_TABLE("mcp4017-502", MCP4018_502), 109158821Sjoel MCP4018_ID_TABLE("mcp4017-103", MCP4018_103), 110158821Sjoel MCP4018_ID_TABLE("mcp4017-503", MCP4018_503), 111158821Sjoel MCP4018_ID_TABLE("mcp4017-104", MCP4018_104), 112162893Sru MCP4018_ID_TABLE("mcp4018-502", MCP4018_502), 113158821Sjoel MCP4018_ID_TABLE("mcp4018-103", MCP4018_103), 114158821Sjoel MCP4018_ID_TABLE("mcp4018-503", MCP4018_503), 115158821Sjoel MCP4018_ID_TABLE("mcp4018-104", MCP4018_104), 116158821Sjoel MCP4018_ID_TABLE("mcp4019-502", MCP4018_502), 117158821Sjoel MCP4018_ID_TABLE("mcp4019-103", MCP4018_103), 118158821Sjoel MCP4018_ID_TABLE("mcp4019-503", MCP4018_503), 119158821Sjoel MCP4018_ID_TABLE("mcp4019-104", MCP4018_104), 120158821Sjoel { /* sentinel */ } 121158821Sjoel}; 122158821SjoelMODULE_DEVICE_TABLE(i2c, mcp4018_id); 123158821Sjoel 124158821Sjoel#define MCP4018_COMPATIBLE(of_compatible, cfg) { \ 125158821Sjoel .compatible = of_compatible, \ 126158821Sjoel .data = &mcp4018_cfg[cfg], \ 127158821Sjoel} 128158821Sjoel 129158821Sjoelstatic const struct of_device_id mcp4018_of_match[] = { 130158821Sjoel MCP4018_COMPATIBLE("microchip,mcp4017-502", MCP4018_502), 131158821Sjoel MCP4018_COMPATIBLE("microchip,mcp4017-103", MCP4018_103), 132238612Szeising MCP4018_COMPATIBLE("microchip,mcp4017-503", MCP4018_503), 133 MCP4018_COMPATIBLE("microchip,mcp4017-104", MCP4018_104), 134 MCP4018_COMPATIBLE("microchip,mcp4018-502", MCP4018_502), 135 MCP4018_COMPATIBLE("microchip,mcp4018-103", MCP4018_103), 136 MCP4018_COMPATIBLE("microchip,mcp4018-503", MCP4018_503), 137 MCP4018_COMPATIBLE("microchip,mcp4018-104", MCP4018_104), 138 MCP4018_COMPATIBLE("microchip,mcp4019-502", MCP4018_502), 139 MCP4018_COMPATIBLE("microchip,mcp4019-103", MCP4018_103), 140 MCP4018_COMPATIBLE("microchip,mcp4019-503", MCP4018_503), 141 MCP4018_COMPATIBLE("microchip,mcp4019-104", MCP4018_104), 142 { /* sentinel */ } 143}; 144MODULE_DEVICE_TABLE(of, mcp4018_of_match); 145 146static int mcp4018_probe(struct i2c_client *client) 147{ 148 struct device *dev = &client->dev; 149 struct mcp4018_data *data; 150 struct iio_dev *indio_dev; 151 152 if (!i2c_check_functionality(client->adapter, 153 I2C_FUNC_SMBUS_BYTE)) { 154 dev_err(dev, "SMBUS Byte transfers not supported\n"); 155 return -EOPNOTSUPP; 156 } 157 158 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 159 if (!indio_dev) 160 return -ENOMEM; 161 data = iio_priv(indio_dev); 162 i2c_set_clientdata(client, indio_dev); 163 data->client = client; 164 165 data->cfg = i2c_get_match_data(client); 166 167 indio_dev->info = &mcp4018_info; 168 indio_dev->channels = &mcp4018_channel; 169 indio_dev->num_channels = 1; 170 indio_dev->name = client->name; 171 172 return devm_iio_device_register(dev, indio_dev); 173} 174 175static struct i2c_driver mcp4018_driver = { 176 .driver = { 177 .name = "mcp4018", 178 .of_match_table = mcp4018_of_match, 179 }, 180 .probe = mcp4018_probe, 181 .id_table = mcp4018_id, 182}; 183 184module_i2c_driver(mcp4018_driver); 185 186MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); 187MODULE_DESCRIPTION("MCP4018 digital potentiometer"); 188MODULE_LICENSE("GPL v2"); 189