1c05dc2ccSPeter Rosin /* 2c05dc2ccSPeter Rosin * Industrial I/O driver for Microchip digital potentiometers 3c05dc2ccSPeter Rosin * Copyright (c) 2015 Axentia Technologies AB 4c05dc2ccSPeter Rosin * Author: Peter Rosin <peda@axentia.se> 5c05dc2ccSPeter Rosin * 6c05dc2ccSPeter Rosin * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf 7c05dc2ccSPeter Rosin * 8c05dc2ccSPeter Rosin * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address 9c05dc2ccSPeter Rosin * mcp4531 1 129 5, 10, 50, 100 010111x 10c05dc2ccSPeter Rosin * mcp4532 1 129 5, 10, 50, 100 01011xx 11294ea6f3SFlorian Vaussard * mcp4541 1 129 5, 10, 50, 100 010111x 12294ea6f3SFlorian Vaussard * mcp4542 1 129 5, 10, 50, 100 01011xx 13c05dc2ccSPeter Rosin * mcp4551 1 257 5, 10, 50, 100 010111x 14c05dc2ccSPeter Rosin * mcp4552 1 257 5, 10, 50, 100 01011xx 15294ea6f3SFlorian Vaussard * mcp4561 1 257 5, 10, 50, 100 010111x 16294ea6f3SFlorian Vaussard * mcp4562 1 257 5, 10, 50, 100 01011xx 17c05dc2ccSPeter Rosin * mcp4631 2 129 5, 10, 50, 100 0101xxx 18c05dc2ccSPeter Rosin * mcp4632 2 129 5, 10, 50, 100 01011xx 19294ea6f3SFlorian Vaussard * mcp4641 2 129 5, 10, 50, 100 0101xxx 20294ea6f3SFlorian Vaussard * mcp4642 2 129 5, 10, 50, 100 01011xx 21c05dc2ccSPeter Rosin * mcp4651 2 257 5, 10, 50, 100 0101xxx 22c05dc2ccSPeter Rosin * mcp4652 2 257 5, 10, 50, 100 01011xx 23294ea6f3SFlorian Vaussard * mcp4661 2 257 5, 10, 50, 100 0101xxx 24294ea6f3SFlorian Vaussard * mcp4662 2 257 5, 10, 50, 100 01011xx 25c05dc2ccSPeter Rosin * 26c05dc2ccSPeter Rosin * This program is free software; you can redistribute it and/or modify it 27c05dc2ccSPeter Rosin * under the terms of the GNU General Public License version 2 as published by 28c05dc2ccSPeter Rosin * the Free Software Foundation. 29c05dc2ccSPeter Rosin */ 30c05dc2ccSPeter Rosin 31c05dc2ccSPeter Rosin #include <linux/module.h> 32c05dc2ccSPeter Rosin #include <linux/i2c.h> 33c05dc2ccSPeter Rosin #include <linux/err.h> 342dc2e189SFlorian Vaussard #include <linux/of.h> 352dc2e189SFlorian Vaussard #include <linux/of_device.h> 36c05dc2ccSPeter Rosin 37c05dc2ccSPeter Rosin #include <linux/iio/iio.h> 38c05dc2ccSPeter Rosin 39c05dc2ccSPeter Rosin struct mcp4531_cfg { 40c05dc2ccSPeter Rosin int wipers; 412704e300SPeter Rosin int avail[3]; 42c05dc2ccSPeter Rosin int kohms; 43c05dc2ccSPeter Rosin }; 44c05dc2ccSPeter Rosin 45c05dc2ccSPeter Rosin enum mcp4531_type { 46c05dc2ccSPeter Rosin MCP453x_502, 47c05dc2ccSPeter Rosin MCP453x_103, 48c05dc2ccSPeter Rosin MCP453x_503, 49c05dc2ccSPeter Rosin MCP453x_104, 50294ea6f3SFlorian Vaussard MCP454x_502, 51294ea6f3SFlorian Vaussard MCP454x_103, 52294ea6f3SFlorian Vaussard MCP454x_503, 53294ea6f3SFlorian Vaussard MCP454x_104, 54c05dc2ccSPeter Rosin MCP455x_502, 55c05dc2ccSPeter Rosin MCP455x_103, 56c05dc2ccSPeter Rosin MCP455x_503, 57c05dc2ccSPeter Rosin MCP455x_104, 58294ea6f3SFlorian Vaussard MCP456x_502, 59294ea6f3SFlorian Vaussard MCP456x_103, 60294ea6f3SFlorian Vaussard MCP456x_503, 61294ea6f3SFlorian Vaussard MCP456x_104, 62c05dc2ccSPeter Rosin MCP463x_502, 63c05dc2ccSPeter Rosin MCP463x_103, 64c05dc2ccSPeter Rosin MCP463x_503, 65c05dc2ccSPeter Rosin MCP463x_104, 66294ea6f3SFlorian Vaussard MCP464x_502, 67294ea6f3SFlorian Vaussard MCP464x_103, 68294ea6f3SFlorian Vaussard MCP464x_503, 69294ea6f3SFlorian Vaussard MCP464x_104, 70c05dc2ccSPeter Rosin MCP465x_502, 71c05dc2ccSPeter Rosin MCP465x_103, 72c05dc2ccSPeter Rosin MCP465x_503, 73c05dc2ccSPeter Rosin MCP465x_104, 74294ea6f3SFlorian Vaussard MCP466x_502, 75294ea6f3SFlorian Vaussard MCP466x_103, 76294ea6f3SFlorian Vaussard MCP466x_503, 77294ea6f3SFlorian Vaussard MCP466x_104, 78c05dc2ccSPeter Rosin }; 79c05dc2ccSPeter Rosin 80c05dc2ccSPeter Rosin static const struct mcp4531_cfg mcp4531_cfg[] = { 812704e300SPeter Rosin [MCP453x_502] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 5, }, 822704e300SPeter Rosin [MCP453x_103] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 10, }, 832704e300SPeter Rosin [MCP453x_503] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 50, }, 842704e300SPeter Rosin [MCP453x_104] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 100, }, 852704e300SPeter Rosin [MCP454x_502] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 5, }, 862704e300SPeter Rosin [MCP454x_103] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 10, }, 872704e300SPeter Rosin [MCP454x_503] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 50, }, 882704e300SPeter Rosin [MCP454x_104] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 100, }, 892704e300SPeter Rosin [MCP455x_502] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 5, }, 902704e300SPeter Rosin [MCP455x_103] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 10, }, 912704e300SPeter Rosin [MCP455x_503] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 50, }, 922704e300SPeter Rosin [MCP455x_104] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 100, }, 932704e300SPeter Rosin [MCP456x_502] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 5, }, 942704e300SPeter Rosin [MCP456x_103] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 10, }, 952704e300SPeter Rosin [MCP456x_503] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 50, }, 962704e300SPeter Rosin [MCP456x_104] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 100, }, 972704e300SPeter Rosin [MCP463x_502] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 5, }, 982704e300SPeter Rosin [MCP463x_103] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 10, }, 992704e300SPeter Rosin [MCP463x_503] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 50, }, 1002704e300SPeter Rosin [MCP463x_104] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 100, }, 1012704e300SPeter Rosin [MCP464x_502] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 5, }, 1022704e300SPeter Rosin [MCP464x_103] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 10, }, 1032704e300SPeter Rosin [MCP464x_503] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 50, }, 1042704e300SPeter Rosin [MCP464x_104] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 100, }, 1052704e300SPeter Rosin [MCP465x_502] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 5, }, 1062704e300SPeter Rosin [MCP465x_103] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 10, }, 1072704e300SPeter Rosin [MCP465x_503] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 50, }, 1082704e300SPeter Rosin [MCP465x_104] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 100, }, 1092704e300SPeter Rosin [MCP466x_502] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 5, }, 1102704e300SPeter Rosin [MCP466x_103] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 10, }, 1112704e300SPeter Rosin [MCP466x_503] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 50, }, 1122704e300SPeter Rosin [MCP466x_104] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 100, }, 113c05dc2ccSPeter Rosin }; 114c05dc2ccSPeter Rosin 115c05dc2ccSPeter Rosin #define MCP4531_WRITE (0 << 2) 116c05dc2ccSPeter Rosin #define MCP4531_INCR (1 << 2) 117c05dc2ccSPeter Rosin #define MCP4531_DECR (2 << 2) 118c05dc2ccSPeter Rosin #define MCP4531_READ (3 << 2) 119c05dc2ccSPeter Rosin 120c05dc2ccSPeter Rosin #define MCP4531_WIPER_SHIFT (4) 121c05dc2ccSPeter Rosin 122c05dc2ccSPeter Rosin struct mcp4531_data { 123c05dc2ccSPeter Rosin struct i2c_client *client; 12491307cbeSSlawomir Stepien const struct mcp4531_cfg *cfg; 125c05dc2ccSPeter Rosin }; 126c05dc2ccSPeter Rosin 127c05dc2ccSPeter Rosin #define MCP4531_CHANNEL(ch) { \ 128c05dc2ccSPeter Rosin .type = IIO_RESISTANCE, \ 129c05dc2ccSPeter Rosin .indexed = 1, \ 130c05dc2ccSPeter Rosin .output = 1, \ 131c05dc2ccSPeter Rosin .channel = (ch), \ 132c05dc2ccSPeter Rosin .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 133c05dc2ccSPeter Rosin .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 1342704e300SPeter Rosin .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW), \ 135c05dc2ccSPeter Rosin } 136c05dc2ccSPeter Rosin 137c05dc2ccSPeter Rosin static const struct iio_chan_spec mcp4531_channels[] = { 138c05dc2ccSPeter Rosin MCP4531_CHANNEL(0), 139c05dc2ccSPeter Rosin MCP4531_CHANNEL(1), 140c05dc2ccSPeter Rosin }; 141c05dc2ccSPeter Rosin 142c05dc2ccSPeter Rosin static int mcp4531_read_raw(struct iio_dev *indio_dev, 143c05dc2ccSPeter Rosin struct iio_chan_spec const *chan, 144c05dc2ccSPeter Rosin int *val, int *val2, long mask) 145c05dc2ccSPeter Rosin { 146c05dc2ccSPeter Rosin struct mcp4531_data *data = iio_priv(indio_dev); 147c05dc2ccSPeter Rosin int address = chan->channel << MCP4531_WIPER_SHIFT; 148c05dc2ccSPeter Rosin s32 ret; 149c05dc2ccSPeter Rosin 150c05dc2ccSPeter Rosin switch (mask) { 151c05dc2ccSPeter Rosin case IIO_CHAN_INFO_RAW: 152c05dc2ccSPeter Rosin ret = i2c_smbus_read_word_swapped(data->client, 153c05dc2ccSPeter Rosin MCP4531_READ | address); 154c05dc2ccSPeter Rosin if (ret < 0) 155c05dc2ccSPeter Rosin return ret; 156c05dc2ccSPeter Rosin *val = ret; 157c05dc2ccSPeter Rosin return IIO_VAL_INT; 158c05dc2ccSPeter Rosin case IIO_CHAN_INFO_SCALE: 15991307cbeSSlawomir Stepien *val = 1000 * data->cfg->kohms; 1602704e300SPeter Rosin *val2 = data->cfg->avail[2]; 161c05dc2ccSPeter Rosin return IIO_VAL_FRACTIONAL; 162c05dc2ccSPeter Rosin } 163c05dc2ccSPeter Rosin 164c05dc2ccSPeter Rosin return -EINVAL; 165c05dc2ccSPeter Rosin } 166c05dc2ccSPeter Rosin 1672704e300SPeter Rosin static int mcp4531_read_avail(struct iio_dev *indio_dev, 1682704e300SPeter Rosin struct iio_chan_spec const *chan, 1692704e300SPeter Rosin const int **vals, int *type, int *length, 1702704e300SPeter Rosin long mask) 1712704e300SPeter Rosin { 1722704e300SPeter Rosin struct mcp4531_data *data = iio_priv(indio_dev); 1732704e300SPeter Rosin 1742704e300SPeter Rosin switch (mask) { 1752704e300SPeter Rosin case IIO_CHAN_INFO_RAW: 1762704e300SPeter Rosin *length = ARRAY_SIZE(data->cfg->avail); 1772704e300SPeter Rosin *vals = data->cfg->avail; 1782704e300SPeter Rosin *type = IIO_VAL_INT; 1792704e300SPeter Rosin return IIO_AVAIL_RANGE; 1802704e300SPeter Rosin } 1812704e300SPeter Rosin 1822704e300SPeter Rosin return -EINVAL; 1832704e300SPeter Rosin } 1842704e300SPeter Rosin 185c05dc2ccSPeter Rosin static int mcp4531_write_raw(struct iio_dev *indio_dev, 186c05dc2ccSPeter Rosin struct iio_chan_spec const *chan, 187c05dc2ccSPeter Rosin int val, int val2, long mask) 188c05dc2ccSPeter Rosin { 189c05dc2ccSPeter Rosin struct mcp4531_data *data = iio_priv(indio_dev); 190c05dc2ccSPeter Rosin int address = chan->channel << MCP4531_WIPER_SHIFT; 191c05dc2ccSPeter Rosin 192c05dc2ccSPeter Rosin switch (mask) { 193c05dc2ccSPeter Rosin case IIO_CHAN_INFO_RAW: 1942704e300SPeter Rosin if (val > data->cfg->avail[2] || val < 0) 195c05dc2ccSPeter Rosin return -EINVAL; 196c05dc2ccSPeter Rosin break; 197c05dc2ccSPeter Rosin default: 198c05dc2ccSPeter Rosin return -EINVAL; 199c05dc2ccSPeter Rosin } 200c05dc2ccSPeter Rosin 201c05dc2ccSPeter Rosin return i2c_smbus_write_byte_data(data->client, 202c05dc2ccSPeter Rosin MCP4531_WRITE | address | (val >> 8), 203c05dc2ccSPeter Rosin val & 0xff); 204c05dc2ccSPeter Rosin } 205c05dc2ccSPeter Rosin 206c05dc2ccSPeter Rosin static const struct iio_info mcp4531_info = { 207c05dc2ccSPeter Rosin .read_raw = mcp4531_read_raw, 2082704e300SPeter Rosin .read_avail = mcp4531_read_avail, 209c05dc2ccSPeter Rosin .write_raw = mcp4531_write_raw, 210c05dc2ccSPeter Rosin .driver_module = THIS_MODULE, 211c05dc2ccSPeter Rosin }; 212c05dc2ccSPeter Rosin 2132dc2e189SFlorian Vaussard #ifdef CONFIG_OF 2142dc2e189SFlorian Vaussard 2152dc2e189SFlorian Vaussard #define MCP4531_COMPATIBLE(of_compatible, cfg) { \ 2162dc2e189SFlorian Vaussard .compatible = of_compatible, \ 2172dc2e189SFlorian Vaussard .data = &mcp4531_cfg[cfg], \ 2182dc2e189SFlorian Vaussard } 2192dc2e189SFlorian Vaussard 2202dc2e189SFlorian Vaussard static const struct of_device_id mcp4531_of_match[] = { 2212dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4531-502", MCP453x_502), 2222dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4531-103", MCP453x_103), 2232dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4531-503", MCP453x_503), 2242dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4531-104", MCP453x_104), 2252dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4532-502", MCP453x_502), 2262dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4532-103", MCP453x_103), 2272dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4532-503", MCP453x_503), 2282dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4532-104", MCP453x_104), 2292dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4541-502", MCP454x_502), 2302dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4541-103", MCP454x_103), 2312dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4541-503", MCP454x_503), 2322dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4541-104", MCP454x_104), 2332dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4542-502", MCP454x_502), 2342dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4542-103", MCP454x_103), 2352dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4542-503", MCP454x_503), 2362dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4542-104", MCP454x_104), 2372dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4551-502", MCP455x_502), 2382dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4551-103", MCP455x_103), 2392dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4551-503", MCP455x_503), 2402dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4551-104", MCP455x_104), 2412dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4552-502", MCP455x_502), 2422dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4552-103", MCP455x_103), 2432dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4552-503", MCP455x_503), 2442dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4552-104", MCP455x_104), 2452dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4561-502", MCP456x_502), 2462dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4561-103", MCP456x_103), 2472dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4561-503", MCP456x_503), 2482dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4561-104", MCP456x_104), 2492dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4562-502", MCP456x_502), 2502dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4562-103", MCP456x_103), 2512dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4562-503", MCP456x_503), 2522dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4562-104", MCP456x_104), 2532dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4631-502", MCP463x_502), 2542dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4631-103", MCP463x_103), 2552dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4631-503", MCP463x_503), 2562dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4631-104", MCP463x_104), 2572dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4632-502", MCP463x_502), 2582dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4632-103", MCP463x_103), 2592dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4632-503", MCP463x_503), 2602dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4632-104", MCP463x_104), 2612dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4641-502", MCP464x_502), 2622dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4641-103", MCP464x_103), 2632dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4641-503", MCP464x_503), 2642dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4641-104", MCP464x_104), 2652dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4642-502", MCP464x_502), 2662dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4642-103", MCP464x_103), 2672dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4642-503", MCP464x_503), 2682dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4642-104", MCP464x_104), 2692dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4651-502", MCP465x_502), 2702dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4651-103", MCP465x_103), 2712dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4651-503", MCP465x_503), 2722dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4651-104", MCP465x_104), 2732dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4652-502", MCP465x_502), 2742dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4652-103", MCP465x_103), 2752dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4652-503", MCP465x_503), 2762dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4652-104", MCP465x_104), 2772dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4661-502", MCP466x_502), 2782dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4661-103", MCP466x_103), 2792dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4661-503", MCP466x_503), 2802dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4661-104", MCP466x_104), 2812dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4662-502", MCP466x_502), 2822dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103), 2832dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503), 2842dc2e189SFlorian Vaussard MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104), 2852dc2e189SFlorian Vaussard { /* sentinel */ } 2862dc2e189SFlorian Vaussard }; 287*9c6e4efdSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, mcp4531_of_match); 2882dc2e189SFlorian Vaussard #endif 2892dc2e189SFlorian Vaussard 290c05dc2ccSPeter Rosin static int mcp4531_probe(struct i2c_client *client, 291c05dc2ccSPeter Rosin const struct i2c_device_id *id) 292c05dc2ccSPeter Rosin { 293c05dc2ccSPeter Rosin struct device *dev = &client->dev; 294c05dc2ccSPeter Rosin struct mcp4531_data *data; 295c05dc2ccSPeter Rosin struct iio_dev *indio_dev; 2962dc2e189SFlorian Vaussard const struct of_device_id *match; 297c05dc2ccSPeter Rosin 298c05dc2ccSPeter Rosin if (!i2c_check_functionality(client->adapter, 299c05dc2ccSPeter Rosin I2C_FUNC_SMBUS_WORD_DATA)) { 300c05dc2ccSPeter Rosin dev_err(dev, "SMBUS Word Data not supported\n"); 301f8d9d3b4SMatt Ranostay return -EOPNOTSUPP; 302c05dc2ccSPeter Rosin } 303c05dc2ccSPeter Rosin 304c05dc2ccSPeter Rosin indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 305c05dc2ccSPeter Rosin if (!indio_dev) 306c05dc2ccSPeter Rosin return -ENOMEM; 307c05dc2ccSPeter Rosin data = iio_priv(indio_dev); 308c05dc2ccSPeter Rosin i2c_set_clientdata(client, indio_dev); 309c05dc2ccSPeter Rosin data->client = client; 3102dc2e189SFlorian Vaussard 3112dc2e189SFlorian Vaussard match = of_match_device(of_match_ptr(mcp4531_of_match), dev); 3122dc2e189SFlorian Vaussard if (match) 3132dc2e189SFlorian Vaussard data->cfg = of_device_get_match_data(dev); 3142dc2e189SFlorian Vaussard else 31591307cbeSSlawomir Stepien data->cfg = &mcp4531_cfg[id->driver_data]; 316c05dc2ccSPeter Rosin 317c05dc2ccSPeter Rosin indio_dev->dev.parent = dev; 318c05dc2ccSPeter Rosin indio_dev->info = &mcp4531_info; 319c05dc2ccSPeter Rosin indio_dev->channels = mcp4531_channels; 32091307cbeSSlawomir Stepien indio_dev->num_channels = data->cfg->wipers; 321c05dc2ccSPeter Rosin indio_dev->name = client->name; 322c05dc2ccSPeter Rosin 323c05dc2ccSPeter Rosin return devm_iio_device_register(dev, indio_dev); 324c05dc2ccSPeter Rosin } 325c05dc2ccSPeter Rosin 326c05dc2ccSPeter Rosin static const struct i2c_device_id mcp4531_id[] = { 327c05dc2ccSPeter Rosin { "mcp4531-502", MCP453x_502 }, 328c05dc2ccSPeter Rosin { "mcp4531-103", MCP453x_103 }, 329c05dc2ccSPeter Rosin { "mcp4531-503", MCP453x_503 }, 330c05dc2ccSPeter Rosin { "mcp4531-104", MCP453x_104 }, 331c05dc2ccSPeter Rosin { "mcp4532-502", MCP453x_502 }, 332c05dc2ccSPeter Rosin { "mcp4532-103", MCP453x_103 }, 333c05dc2ccSPeter Rosin { "mcp4532-503", MCP453x_503 }, 334c05dc2ccSPeter Rosin { "mcp4532-104", MCP453x_104 }, 335294ea6f3SFlorian Vaussard { "mcp4541-502", MCP454x_502 }, 336294ea6f3SFlorian Vaussard { "mcp4541-103", MCP454x_103 }, 337294ea6f3SFlorian Vaussard { "mcp4541-503", MCP454x_503 }, 338294ea6f3SFlorian Vaussard { "mcp4541-104", MCP454x_104 }, 339294ea6f3SFlorian Vaussard { "mcp4542-502", MCP454x_502 }, 340294ea6f3SFlorian Vaussard { "mcp4542-103", MCP454x_103 }, 341294ea6f3SFlorian Vaussard { "mcp4542-503", MCP454x_503 }, 342294ea6f3SFlorian Vaussard { "mcp4542-104", MCP454x_104 }, 343c05dc2ccSPeter Rosin { "mcp4551-502", MCP455x_502 }, 344c05dc2ccSPeter Rosin { "mcp4551-103", MCP455x_103 }, 345c05dc2ccSPeter Rosin { "mcp4551-503", MCP455x_503 }, 346c05dc2ccSPeter Rosin { "mcp4551-104", MCP455x_104 }, 347c05dc2ccSPeter Rosin { "mcp4552-502", MCP455x_502 }, 348c05dc2ccSPeter Rosin { "mcp4552-103", MCP455x_103 }, 349c05dc2ccSPeter Rosin { "mcp4552-503", MCP455x_503 }, 350c05dc2ccSPeter Rosin { "mcp4552-104", MCP455x_104 }, 351294ea6f3SFlorian Vaussard { "mcp4561-502", MCP456x_502 }, 352294ea6f3SFlorian Vaussard { "mcp4561-103", MCP456x_103 }, 353294ea6f3SFlorian Vaussard { "mcp4561-503", MCP456x_503 }, 354294ea6f3SFlorian Vaussard { "mcp4561-104", MCP456x_104 }, 355294ea6f3SFlorian Vaussard { "mcp4562-502", MCP456x_502 }, 356294ea6f3SFlorian Vaussard { "mcp4562-103", MCP456x_103 }, 357294ea6f3SFlorian Vaussard { "mcp4562-503", MCP456x_503 }, 358294ea6f3SFlorian Vaussard { "mcp4562-104", MCP456x_104 }, 359c05dc2ccSPeter Rosin { "mcp4631-502", MCP463x_502 }, 360c05dc2ccSPeter Rosin { "mcp4631-103", MCP463x_103 }, 361c05dc2ccSPeter Rosin { "mcp4631-503", MCP463x_503 }, 362c05dc2ccSPeter Rosin { "mcp4631-104", MCP463x_104 }, 363c05dc2ccSPeter Rosin { "mcp4632-502", MCP463x_502 }, 364c05dc2ccSPeter Rosin { "mcp4632-103", MCP463x_103 }, 365c05dc2ccSPeter Rosin { "mcp4632-503", MCP463x_503 }, 366c05dc2ccSPeter Rosin { "mcp4632-104", MCP463x_104 }, 367294ea6f3SFlorian Vaussard { "mcp4641-502", MCP464x_502 }, 368294ea6f3SFlorian Vaussard { "mcp4641-103", MCP464x_103 }, 369294ea6f3SFlorian Vaussard { "mcp4641-503", MCP464x_503 }, 370294ea6f3SFlorian Vaussard { "mcp4641-104", MCP464x_104 }, 371294ea6f3SFlorian Vaussard { "mcp4642-502", MCP464x_502 }, 372294ea6f3SFlorian Vaussard { "mcp4642-103", MCP464x_103 }, 373294ea6f3SFlorian Vaussard { "mcp4642-503", MCP464x_503 }, 374294ea6f3SFlorian Vaussard { "mcp4642-104", MCP464x_104 }, 375c05dc2ccSPeter Rosin { "mcp4651-502", MCP465x_502 }, 376c05dc2ccSPeter Rosin { "mcp4651-103", MCP465x_103 }, 377c05dc2ccSPeter Rosin { "mcp4651-503", MCP465x_503 }, 378c05dc2ccSPeter Rosin { "mcp4651-104", MCP465x_104 }, 379c05dc2ccSPeter Rosin { "mcp4652-502", MCP465x_502 }, 380c05dc2ccSPeter Rosin { "mcp4652-103", MCP465x_103 }, 381c05dc2ccSPeter Rosin { "mcp4652-503", MCP465x_503 }, 382c05dc2ccSPeter Rosin { "mcp4652-104", MCP465x_104 }, 383294ea6f3SFlorian Vaussard { "mcp4661-502", MCP466x_502 }, 384294ea6f3SFlorian Vaussard { "mcp4661-103", MCP466x_103 }, 385294ea6f3SFlorian Vaussard { "mcp4661-503", MCP466x_503 }, 386294ea6f3SFlorian Vaussard { "mcp4661-104", MCP466x_104 }, 387294ea6f3SFlorian Vaussard { "mcp4662-502", MCP466x_502 }, 388294ea6f3SFlorian Vaussard { "mcp4662-103", MCP466x_103 }, 389294ea6f3SFlorian Vaussard { "mcp4662-503", MCP466x_503 }, 390294ea6f3SFlorian Vaussard { "mcp4662-104", MCP466x_104 }, 391c05dc2ccSPeter Rosin {} 392c05dc2ccSPeter Rosin }; 393c05dc2ccSPeter Rosin MODULE_DEVICE_TABLE(i2c, mcp4531_id); 394c05dc2ccSPeter Rosin 395c05dc2ccSPeter Rosin static struct i2c_driver mcp4531_driver = { 396c05dc2ccSPeter Rosin .driver = { 397c05dc2ccSPeter Rosin .name = "mcp4531", 3982dc2e189SFlorian Vaussard .of_match_table = of_match_ptr(mcp4531_of_match), 399c05dc2ccSPeter Rosin }, 400c05dc2ccSPeter Rosin .probe = mcp4531_probe, 401c05dc2ccSPeter Rosin .id_table = mcp4531_id, 402c05dc2ccSPeter Rosin }; 403c05dc2ccSPeter Rosin 404c05dc2ccSPeter Rosin module_i2c_driver(mcp4531_driver); 405c05dc2ccSPeter Rosin 406c05dc2ccSPeter Rosin MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); 407c05dc2ccSPeter Rosin MODULE_DESCRIPTION("MCP4531 digital potentiometer"); 408c05dc2ccSPeter Rosin MODULE_LICENSE("GPL"); 409